{"id":17946555,"url":"https://github.com/dotpep/microservices-communication","last_synced_at":"2026-04-11T17:43:16.799Z","repository":{"id":259965392,"uuid":"879930838","full_name":"dotpep/microservices-communication","owner":"dotpep","description":"Represents Microservices Communication with Event Driven Architecture with DI, REST API, gRPC, API Gateway, RabbitMQ, Docker and Kubernates or K8s - services written on Golang rollback: Dotnet.","archived":false,"fork":false,"pushed_at":"2024-12-03T00:09:37.000Z","size":151,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T14:45:35.168Z","etag":null,"topics":["api-gateway","asp-net-core","csharp","docker","dotnet","event-driven","go-gin","golang","grpc","k8s","kubernetes","microservices","rabbitmq","rest-api"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dotpep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-28T19:59:22.000Z","updated_at":"2024-12-03T00:09:41.000Z","dependencies_parsed_at":"2025-02-09T03:40:38.311Z","dependency_job_id":"99c85b8f-9570-45bf-a7b9-6292561d2f53","html_url":"https://github.com/dotpep/microservices-communication","commit_stats":null,"previous_names":["dotpep/microservices-communication"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dotpep/microservices-communication","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotpep%2Fmicroservices-communication","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotpep%2Fmicroservices-communication/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotpep%2Fmicroservices-communication/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotpep%2Fmicroservices-communication/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dotpep","download_url":"https://codeload.github.com/dotpep/microservices-communication/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotpep%2Fmicroservices-communication/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279007311,"owners_count":26084280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-gateway","asp-net-core","csharp","docker","dotnet","event-driven","go-gin","golang","grpc","k8s","kubernetes","microservices","rabbitmq","rest-api"],"created_at":"2024-10-29T07:06:13.116Z","updated_at":"2025-10-11T13:12:08.540Z","avatar_url":"https://github.com/dotpep.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Microservices Communication in Dotnet Implementation\n\n**Tech Stack:**\n\n- Dotnet C# (will be switched/implemented on Golang this two services)\n- Two Services\n- Event Driven Architecture\n- SQL and InMemory (Cache) Databases\n- REST API\n- API Gateway (Ingress Nginx Controller, Ingress Nginx Load Balancer)\n- gRPC (sync)\n- RabbitMQ (async) Event/Message Bus, Producer/Consumer\n- Docker\n- K8s\n\n**SRC's:**\n\n- [.NET Microservices YT](https://youtu.be/DgVjEo3OGBI?si=SRhBSwyhBf85bbRg)\n\n## TO DO\n\n- Come Up with other microservices for this project\n- [ ] Database ER-D Schemas\n- [ ] API Documentation (Swagger/OpenAPI)\n- [ ] Architectural Solution/Microservices Communication (images of Schemas...)\n\n- [ ] Add SQL Server or other Database for CommandsService in production (and InMemory DB in development)\n\n---\n\n**Golang:**\n\n- Transition to Golang Microservices (From DotNET)\n    - How to use Golang PlatformService (instead of Dotnet)\n    - is it needed? need I delete them?\n    - where to store Dotnet service? what is fallback?\n- migrate/convert Dotnet PlatformService to Golang PlatformService (PlatformServiceGo)\n- how to structure Golang project\n- Golang Event-Driven Architecture\n\n## Services\n\n- PlatformService\n- CommandsService\n\nServices Response Example:\n\n```json\n```\n\n## Demonstrations, Solution Architecture\n\n`System Design and Software/Service Architecuture`\n\nSchemas, Diagrams, UMLs, OpenAPI/Swagger endpoints docs img's:\n\n## Documentation\n\n### API Endpoints (Dotnet)\n\n**PlatformService:**\n\n- GET: `/api/platforms` Get Lists of All Platforms\n- GET: `/api/platforms/1` Get Specific One Platform\n- POST: `/api/platforms/` Create Platform\n\n---\n\n**CommandsService:**\n\n- POST: `/api/c/platforms/` Test Inbound Connection (to PlatformService)\n\n- GET: `/api/c/platforms` Get All Platforms\n- GET: `/api/c/platforms/{platformId}/commands` Get All Commands for a Platform\n- GET: `/api/c/platforms/{platformId}/commands/{commandId}` Get a Specific Command for a Platform\n- POST: `/api/c/platforms/{platformId}/commands/` Create a Command for a Platform\n\n### Database Entities/Schemas (Dotnet)\n\n**PlatformDatabase:**\n\n- Platform\n    - Id\n    - Name\n    - Publisher\n    - Cost\n\n---\n\n**CommandsDatabase:**\n\n- Command\n    - Id\n    - HowTo\n    - CommandLine\n    - PlatformId\n    - Platform (obj)\n\n- Platform\n    - Id\n    - ExternalId\n    - Name\n    - Commands (obj)\n\n## Architecture\n\n### Event Driven Architecture\n\n**Component Layer of EDA:**\n\n- Models\n- DTO's\n- DB Context\n- Repository\n\n---\n\n**Event Driven Architecture (Data):**\n\n- (conn: DB Context) Models - mapped - (conn: Models) DTOs\n- (conn: SQL DB) DB Context - read/write - (conn: DB Context) Repository (goes: Outside)\n- Models is internal and DTOs is extertal.\n\n**Main Components:**\n\n- Models - internal data representation\n- DB Context - mediates models down to persistent layer in Database (SQL Server)\n- DTO's - extensive use of Data Transfer Objects - external representation of our model data and they're mapped to models\n- Repository (Pattern) - just abstract away our DB Context implementation\n- REST API (Controller - sync, in) we will say externally reach into a repository pull back any data and then send back HTTP response using DTO's, it is our external Contract going out to external Consumers\n- Repository Read/Write with DB Context\n\n---\n\n**Models:**\n\nModels with property, data annotations that will be auto validated.\n\n**DB Context:**\n\nDB Context that will connect context to InMemory DB with custom AppDbContext that inherit of DbContext with constructor and property of DbSet with Platform (models) class data type as plural Platforms.\n\n**Repository:**\n\nUses Interface concrete class pattern,\nWe will inject our repository through Dependency Injection (DI), in startup class.\n\nInterface is Contract between apps/services and specifies what type of things,\nmethod signatures effectively that our repository will support,\nand then any concrete class can come along and implement those interfaces.\n\n**DB Preparation:**\n\nIt is for testing in our In-Memory DB, with some generated and populated data in DB.\n\nPut some data to database.\nWe use In-Memory database as temporary database and it is used in tests.\n\n**DTO's:**\n\nDTO's (Data Transfer Object) - external represantataion of our internal models.\n\nIt is like contract for other services,\nif you like will change your Models,\nyou will terminate this contract with other services like API's.\nAbstract your external and internal, like using Interfaces but for DB and data.\n\n- data privacy\n- contractual coupling\n\nMap DTO's:\n\n- Model to PlatformReadDto\n- PlatformCreatDto to Model\n\n**Controller and Actions:**\n\nController - API Endpoints.\nFor testing API, I'm using Insomnia API client.\n\nEndpoint: `http://localhost:5000/api/platforms`\n\n- Get Lists of All Platforms\n- Get Specific One Platform by ID\n- Create Platform\n\n### Other Technologies and Tools\n\n**REST API:**\n\nUses JSON in response, Have endpoints or URI's.\nWorks under HTTP (TCP) and have Header, Body, HTTP Status code and Use GET, POST, PUT, PATCH and DELETE HTTP methods.\n\n---\n\n**HTTP:**\n\nClient requests to REST API.\n\n**HTTP project Use case:**\n\nPlatformService HTTP client sync requests to the CommandsService endpoint,\nto test Inbound Connection and send Platform to the CommandsService.\n\n- PlatformService is the Client\n- request to the CommandsService\n\n---\n\n**gRPC:**\n\n- google Remote Procedure Call (gRPC)\n- One of the API Architecture Style / Type of API Protocol\n- is RPC-based\n- uses HTTP/2 protocol to transport binary messages (inc. TLS)\n- Focused on High Perfomance\n- Relies on Protocol Buffers (aka protobuf) to defined the contract between endpoints\n    - protobuf is just a file/format like .json named `filename.proto` with structured messages,\n    - defines the service, inputs and outputs\n    - exists at both endpoints, client and server\n    - really forms the contract that both parties have and between two services, each other\n- Multi-language support (C# client can call a Golang/Python service)\n- Frequently used as a method of service to service communication\n- gRPC needs to auto generate code using protoc\n\n**gRPC project Use case:**\n\nWhen the CommandsService starts we want to use gRPC,\nto reach out to the PlatformService and retrieve all the Platforms\nthat PlatformService has.\n\nCommandsService is going to reach out at start up,\nand pull Platforms in PlatformService using gRPC,\ndown and it will load ones that it doesn't already have.\n\n- CommandsService is the Client\n- request to the PlatformService\n\n**gRPC in K8s:**\n\nClusterIP service in PlatformService, provide port\nfor gRPC that uses HTTP/2 with TLS or HTTPS.\n\nWe don't have HTTPS running in our cluster.\nWe need to tell that our gRPC to use only HTTP 2 protocol without TLS,\nwith configuration on Kestrel web server running on PlatformService which is server,\nand we tell our Client endpoint to connect to a specific port `777`.\n\n- after changes in `platform-depl.yml` file we need to `kubectl apply -f .\\platforms-depl.yml`\n- when you update service code and build/push image you need to `kubectl rollout restart deployment platform-depl` (`platform-depl` is name of deployment to get it `kubectl get deployments`)\n\n**gRPC use HTTP without TLS for K8s (Dotnet):**\n\n`/PlatformService/appsettings.Production.json`:\n\n```json\n...\n{\n    \"Kestrel\": {\n        \"Endpoints\": {\n            \"Grpc\": {\n                \"Protocols\": \"Http2\",\n                \"Url\": \"http://platforms-clusterip-srv:777\"\n            },\n            \"webApi\": {\n                \"Protocols\": \"Http1\",\n                \"Url\": \"http://platforms-clusterip-srv:80\"\n            }\n        }\n    }\n}\n```\n\n**gRPC Questions:**\n\n- is gRPC synchronous or asynchronous\n\n---\n\n**API Gateway:**\n\nIngress Nginx Controller and Load Balancer in K8s cluster.\n\n---\n\n**RabbitMQ (Message Bus) Architecture:**\n\n`PlatformService` will `Publish` a **message** onto in **RabbitMQ Message Bus**,\nand it doesn't care who is **listening** for those **messages** it's just putting\nthe information out there, it might be one service, or it might me 100 services, might be none,\ndoesn't matter it doesn't care,\nand then on the `CommandService` side, we are going to `Subscribe` for those **events**.\n\n**RabbitMQ Overview:**\n\nRabbitMQ is Message Bus/Message Broker with Queue/Buffer, LIFO, Publisher/Subscriber or Producer/Consumer of Events, Tasks, Messages - Asyncronously.\n\n- A Message Broker - it accepts and forwards messages.\n- Messages are sent by Producers (or Publishers)\n- Messages are received by Consumers (or Subscribers)\n- Messages are stored on Queues (essentially a message buffer) (messages can be stored in the queue, so it has some degree of persistence, we're not going to be using that in our solution, so if our message bus crashes then we use or lose all our messages, but in production type environment you wouldn't do that you would allow messages to persist in the event of any failures)\n- Exchanges can be used to add a degree of \"routing\" functionality (we're going to be using an exchage, but going to be routing)\n- RabbitMQ Uses - Advanced Message Queuing Protocol (AMQP) and others\n\nIdea: Messangers are published onto the queue if your services are overwhelmed and can't actually service those requests the message broker acts as a buffer for those messages and then as and when you bring more services online they kind of chew through the messages on the queue.\n\n**Exchanges in RabbitMQ:**\n\n4 Types of Exchange:\n\n- Direct Exchange\n- Fanout Exchange (we're going to use)\n- Topic Exchange\n- Header Exchange\n\n**Direct Exchange:**\n\n\u003e Service 1 | Message Broker | Service 2\n\n`Publusher (Publish RK=\"somekey\") --\u003e Exchange (Routes to: \"somekey\") -\u003e Queue ||| --\u003e (Consume) Consumer`\n\n- Delivers Messages to queues based on a routing key\n- Ideal for \"direct\" or unicast messaging\n\n**Fanout Exchange:**\n\n\u003e Service 1 | Message Broker | Service 2\n\n`Publisher (Publish) --\u003e Exchange -\u003e Queue 1 |||, Queue 2 ||| --\u003e (Consume) Consumer 1, (Consume) Consumer 2, (Consume) Consumer 3`\n\n- Delivers Messages to all Queues that are bound to the exchange\n- It ignores the routing key\n- Ideal for broadcas messages\n\nDoesn't care who is listening just put messages to Queue.\n\n**RabbitMQ in K8s:**\n\n- K8s RabbitMQ .yml file configuration is not a Production Quality or Production Class deployment.\n\n---\n\n**Message Broker Concepts:**\n\n- Producer\n- Consumer\n- Queue???\n- Message Bus???\n- Events???\n- Exchange???\n- ...\n\nProducer (Publisher) theory:\n\n...\n\n- Connection to Message Broker\n- Message Bus Client\n- Publish new Platform to the Event\n\nConsumer (Subscriber) theory:\n\nMessage Bus Subscriber will run in Background service task and\nwill Listen Event Processor and Queue of Producer Event in Message Bus.\n\n- Event Processor\n- Message Bus Subscriber\n- Background Listener Service\n- Listen the Event\n\n---\n\n**Docker and K8s:**\n\n**Docker Overview:**\n\nDocker is ???.\nDocker Container works above OS with Docker Engine (when VM like Virtual Box uses Hypervisor to make new OS top of your Host OS).\n\nDocker Compose is kind of a middle ground between Docker and K8s,\nthere is also run up muliple containers, network them together,\nit is good option in development type environment/stage\nbut in production-wise K8s is really the option.\n\n**Kubernates Overview:**\n\nKubernates is Container Orchestrator, ...\n\n**Kubernates Architecture:**\n\n`/K8s` is production deployment k8s files\n\nK8s terminology:\n\n- Cluster is\n- Node is\n    - Node port (3xxxx:80) 3xxxx is internal, 80 is external (3xxxx will be generated)\n- Pod is Container Service (like our Platform Service Container) with (80:666)\n- Port mapping is\n    - Cluster IP\n- communcation between K8s\n\nAPI Gateway in K8s:\n\nPod with Ingress Nginx Controller...\n\n**K8s Questions:**\n\n- API Gateway vs Ingress Controller vs Load Balancer vs Reverse Proxy\n- Kubernates Imperative (Command Line) and Declarative (Config Files)\n- K8s microservices directory structure solution\n\n- is it necessary to have HTTPS inside K8ss cluster (because K8s cluster will be internal domain, and that you would terminate TLS at Ingress Nginx Gateway) (we can setup it `TLS certificate using LetsEncrypt, certbot`)\n\n## Running Instructions\n\n- [ ] gRPC Error:\n\n- you need to run PlatformService (gRPC server) first\n- and then run CommandsService (gRPC client, implementation returns null and it is crushing the server!)\n\n## Commands Log\n\n### DotNET\n\nTo start:\n\n`dotnet build`\n`dotnet run`\n\n---\n\nTo configure version:\n\n`dotnet --list-sdks`\n`dotnet --version`\n\n`dotnet new webapi -n PlatformService -f net5.0` - create new webapi project\nwebapi is a template\n-n flag is name of service/app\n-f flag is stands for framework, you can specify version of dotnet like net7.0, net8.0\n\n`code -r .\\PlatformService\\` - open this dir in vs code recursivly\n\n`dotnet new globaljson` - set version of dotnet that will be used in this folder\nchange global.json (version to `dotnet --list-sdks` version):\n\n```json\n{\n  \"sdk\": {\n    \"version\": \"5.0.408\"\n  }\n}\n```\n\n`dotnet add package PackageName -v 5.0.8`\n-v flag is --version\n\n---\n\nto Fix bug:\n\n```bash\ndotnet run\nBuilding...\n--\u003e Seeding Data...\ncrit: Microsoft.AspNetCore.Server.Kestrel[0]\n      Unable to start Kestrel.\n```\n\n[Stackoverflow - Unable to start Kestrel when 'dotnet run'](https://stackoverflow.com/questions/57736568/unable-to-start-kestrel-when-dotnet-run)\n\n1. `dotnet dev-certs https --clean`\n2. `dotnet dev-certs https --trust`\n\n### Golang\n\n### Docker\n\nDocker:\n\n- Dockerfile --\u003e Docker Image\n\npush image to docker hub - `docker build -t dotpep/platformservicedotnet .`\n\n- `docker run -p 8080:80 -d dotpep/platformservicedotnet` (-p flag port, mapping) (-d flag detached) (docker hub image)\n\nCommands:\n\n- `docker run` (start new id container)\n- `docker ps` (what containers are in running)\n- `docker stop \u003ccontainer-id\u003e` (stop container by id)\n- `docker start \u003ccontainer-id\u003e` (restart existed container with id)\n- `docker logs -f \u003ccontainer-id\u003e` (check docker logs, with -f flag attached)\n\nA lot usage:\n\n- `docker push dotpep/platformservicedotnet`\n- `docker build`\n\n### K8s\n\n- `kubectl version`\n- `kubectl apply -f .\\platforms-depl.yml` (`cd .\\K8s\\`)\n- `kubectl get deployments`\n- `kubectl get pods`\n- `kubectl delete deployment \u003cservice-deployments-name\u003e`\n- `kubectl delete pod \u003cname\u003e`\n\n---\n\nIf we try to delete `platformservice` with logs of web-api, k8s will automatically up it, even if we delete it.\n\nFor deletion and stoping you need to delete deployments (when running k8s there will be 2 service container in `docker ps`).\n\n- `kubectl delete deployments platforms-depl`\n\n---\n\nWe have service up and running on K8s cluster\nbut we have no way of accessing it yet.\n\nWe need to create a **Node Port** that will actually give us access to service running in k8s cluster.\n\n- `kubectl apply -f .\\platforms-np-srv.yml`\n- `kubectl get services`\n\nNode Port - 3xxxx will be generated with random!\n\n---\n\nNaming K8s directory .yml files:\n\n- `platforms-depl.tml` platform service deployment\n- `platforms-np-srv.tml` platform node port service\n\n---\n\nSecond Service (CommandService):\n\n- `docker build -t dotpep/commandservicedotnet .`\n- `docker run -p 8080:80 dotpep/commandservicedotnet`\n\nMake `appsettings.Production.json` in PlatformService that sends HttpCommandDataClient to CommandsService:\n\n```json\n{\n    \"CommandService\": \"http://commands-clusterip-srv:80/api/c/platforms\"\n}\n```\n\n- `commands-clusterip-srv:80` is service host in /K8s/commands-depl.yml conf file `ClusterIP` second section\n\nBecause of changes and creating new file, you need to build and push Docker Image to Hub: `docker build -t dotpep/platformservicedotnet .` and `docker push dotpep/platformservicedotnet`\n\n---\n\n- `kubectl get deployments`\n- `kubectl rollout restart deployment platforms-depl`\n- `kubectl logs \u003cpod\u003e -f`\n\n---\n\n- `kubectl apply -f .\\commands-depl.yml`\n\n---\n\nSetting Up - Ingress Nginx Controller (API Gateway)\n\nlinks:\n\n- [github.com/kubernetes/ingress-nginx](https://github.com/kubernetes/ingress-nginx)\n- [kubernetes.github.io/ingress-nginx/deploy/#docker-desktop](https://kubernetes.github.io/ingress-nginx/deploy/#docker-desktop)\n- [raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/aws/deploy.yaml](https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/aws/deploy.yaml)\n\nCommand:\n\n- `kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/aws/deploy.yaml` (in `kubernetes.github.io/ingress-nginx/deploy/#docker-desktop` link)\n\nAdditional:\n\n- `kubectl get namespace`\n- `kubectl get deployments --namespace=ingress-nginx` shows name:`ingress-nginx-controller`\n- `kubectl get pods --namespace=ingress-nginx`\n- `kubectl logs \u003cpod\u003e --namespace=ingress-nginx -f`\n- `kubectl get services --namespace=ingress-nginx` shows name:`ingress-nginx-controller` and type:`LoadBalancer`\n\n---\n\n`ingress-srv.yml`:\n\n- rules: - host: `microcomm.com`\n\nSteps:\n\n- `cd C:\\Windows\\System32\\drivers\\etc`\n- `ls` shows files like `hosts`, `networks`, `protocol`, `services` ...\n- `vim .\\hosts` and add `127.0.0.1 microcomm.com`\n- `cat .\\hosts` ensure that you added it correctly in the end of file\n\nApplying ingress-srv.yml:\n\n- `kubectl apply -f .\\ingress-srv.yml`\n\n```bash\nWarning: annotation \"kubernetes.io/ingress.class\" is deprecated, please use 'spec.ingressClassName' instead\n```\n\nSolution for warning:\n\n- [kubernetes ingress service annotations, kubernetes.io/ingress.class annotation is officially deprecated:](https://stackoverflow.com/questions/64262770/kubernetes-ingress-service-annotations)\n\nTry to Ping this endpoint:\n\n- `http://microcomm.com/api/platforms`\n\n---\n\nCreating Database Storage Pod in K8s cluster:\n\n- `kubectl get storageclass`\n\nThree concepts of Storage K8s:\n\n1. Persistent Volume Claim\n2. Persistent Volume\n3. Storage Class\n\n`local-pvc.yml`:\n\n- `kubectl apply -f .\\local-pvc.yml`\n- `kubectl get pvc`\n\n---\n\nCreating K8s secrets:\n\n- `kubectl create secret generic mssql --from-literal=SA_PASSWORD=\"pas55w0rd!\"`\n- `kubectl create secret generic \u003cmssql-name\u003e --from-literal=\u003cSA_PASSWORD-key\u003e=\"\u003cpas55w0rd!-value\u003e\"`\n\n---\n\n`mssql-plat-depl.yml`:\n\n```yml\n...\n          env:\n          - name: MSSQL_PID\n            value: \"Express\"\n          - name: ACCEPT_EULA\n            value: \"Y\"\n          - name: SA_PASSWORD\n            valueFrom:\n              secretKeyRef:\n                name: \u003cmssql-name\u003e\n                key: \u003cSA_PASSWORD-key\u003e\n```\n\n1. Deployment `msql`\n2. Service `mssql-clusterip-srv` type:`ClusterIP`\n3. Service `mssql-loadbalancer` type:`LoadBalancer`\n\n- `kubectl apply -f .\\mssql-plat-depl.yml`\n- `kubectl get services`\n- `kubectl get pods`\n\n---\n\nConnection to MsSQL (Microsoft SQL Server)\n\nSQLTools and SQLTools Microsoft SQL Server driver (VS Code extentions to connect) (search: `@tag:sqltools-driver mssql` for driver) (SQLTools and MsSQL driver by Matheus Teixeira):\n\nConnection string:\n\n```txt\nServer=localhost,1433;Database=Master;User Id=SA;Password=pas55w0rd!\n```\n\nCommand:\n\n- `docker ps`\n- `docker exec -it \u003cfa8cb70ec39f-CONTAINER-ID-or-Name\u003e /opt/mssql-tools/bin/sqlcmd -S localhost -U sa`\n\nMsSQL type commands:\n\n1. select name from sys.databases;\n2. go\n\n- quit\n\n---\n\n`/PlatformService/appsettings.Production.json`:\n\n- Do not use user as default `SA`/`sa` in `User Id=SA` in Production staging configuration, connection!\n\n```json\n{\n    \"CommandService\": \"http://commands-clusterip-srv:80/api/c/platforms\",\n    \"ConnectionStrings\":\n    {\n        \"PlatformsConn\": \"Server=mssql-clusterip-srv,1433;Initial Catalog=platformsdb;User Id=SA;Password=pas55w0rd!;\"\n    }\n}\n```\n\n---\n\nMigrations of SQLServer in Production and InMemory Seeding data in Development\n\n- `dotnet ef migrations add initialmigration`\n\nIf you get error with `file was not found.` e.g. for `dotnet ef`:\n\n- `dotnet tool install --global dotnet-ef --version 5.*`\n\nLink: [Command dotnet ef not found - Stackoverflow](https://stackoverflow.com/questions/57066856/command-dotnet-ef-not-found)\n\nInMemory Database do not support migrations and we need to do some trick!\n(We are using InMemory DB for Development and SQL Server as for Production)\n\nin `PlatformService/Startup.cs` - (comment it when applying Migrations and uncomment when we done with this, and use it for Development):\n\n```cs\n            // Database\n            //if (_env.IsProduction())\n            //{\n                Console.WriteLine(\"--\u003e Using SqlServer Db\");\n                services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\n                    opt.UseSqlServer(Configuration.GetConnectionString(\"PlatformsConn\"))\n                );\n            //}\n            //else\n            //{\n            //    Console.WriteLine(\"--\u003e Using InMem Db\");\n            //    services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\n            //        opt.UseInMemoryDatabase(\"InMem\")\n            //    );\n            //}\n```\n\nand also:\n\n```cs\n            // Preperation DB\n            //PrepDb.PrepPopulation(app, env.IsProduction());\n```\n\nit will look like after this command (`dotnet ef migrations add initialmigration`):\n\n```bash\nBuild started...\nBuild succeeded.\n--\u003e Using SqlServer Db\n--\u003e CommandService Endpoint http://localhost:6000/api/c/platforms\nDone. To undo this action, use 'ef migrations remove'\n```\n\n- make docker build for image and push it\n- and kubectl restart of platforms-depl deployment\n\nCheck with:\n\n- `docker ps` find mssql Container_ID\n- `docker exec -it \u003ce9dd6791525e-Container_ID\u003e /opt/mssql-tools/bin/sqlcmd -S localhost -U sa`\n- in container Mssql sqlcmd: `select name from sys.databases;`\n- and write `go`\n- this will show databases in sys and also our migrated databases called `platformsdb`\n\nAdditional check in Container MsSQL DB:\n\n- `USE platformsdb;`\n- `go`\n- `SELECT * FROM Platforms;`\n- `go`\n\n---\n\nError Management and Kill Bad Deployment:\n\n- `kubectl delete deployment platforms-depl`\n\n---\n\nRabbitMQ in K8s:\n\n- `kubectl apply -f .\\rabbitmq-depl.yml`\n- `kubectl get deployments`, `kubectl get pods`\n- `kubectl get services` show LoadBalancer and ClusterIP of rabbitmq\n- to see logs: `kubectl get pods` or `docker ps` get Container_ID and `kubectl logs \u003cpod-name\u003e -f` or `docker logs \u003ccontainer-id\u003e -f`\n- Go to: `http://localhost:15672/` for Management Interface\n\nRabbitMQ Management Interface Default Login Credentials:\n\n- username: `guest`\n- password: `guest`\n\nFor Test Publisher (in PlatformService):\n\n- run `make run` or `dotnet run` in `PlatformService`\n- request with POST to this endpoint: `http://localhost:5000/api/platforms`\n- make a lot of requests (you can comment SyncClient instruction in `Controllers/PlatformsController.cs` and in `HttpPost`/`CreatePlatform()` method) and see difference between delay of sync and async.\n- also see graph in `http://localhost:15672/` RabbitMQ Management Interface\n\n```cs\n// POST: /api/platforms\n[HttpPost]\npublic ActionResult\u003cPlatformReadDto\u003e CreatePlatform(PlatformCreateDto platformCreateDto){\n      // Message Broker Client - Send Async Message\n    platformPublishedDto.Event = \"Platform_Published\";\n}\n```\n\n- `platformPublishedDto` has Event property to store which event it is (definition of Event in string format)\n- and for CreatePlatform() controller it will be setted as `Event=\"Platform_Published\"` in PlatformPublishedDto.\n\nFor Test Listener (Consumer) (in CommandsService):\n\n- run (make run) both services PlatformService and CommandsService\n- request POST: `http://localhost:5000/api/platforms` of Creating new Platform in PlatformService\n- check the logs of both services\n- this Platform will be published/consumed with creation of this Platform in the CommandsService\n- and you can use Created Platform ID in CommandsService\n- to ping/request other endpoints like GET: `http://localhost:6000/api/c/platforms` to Get all Platforms in CommandsService (that was consumed via RabbitMQ)\n- or like POST: (provide existing platformId) `http://localhost:6000/api/c/platforms/{platformID}/commands/` to Create Command For Platform\n\n---\n\nRabbitMQ theory:\n\n- Message Bus Publisher (PlatformService)\n- Event Processor/Processing\n- Event Listener (CommandsService)\n\n---\n\nDependency Injection Reasons - when you register your services in config services,\nthey have what's called a service lifetime (they have different lifetimes):\n\n1. Singleton - created 1st time requested, subsequent requests use the same instance (registered services exist for lifetime of the application).\n2. Scoped - same within a request but created for every new request (exist kind of for every kind of session).\n3. Transient - new instance provided everytime, never the same/reused (exist ones every request).\n\nWhen we come on to creating our Listening Service that is going to be created as a Singleton service,\nultimetly it's going to be ther for the lifetime of our application.\nThat service is going to call this service and in order for that to happen in order for us to inject this Event Processor service into our Listening service it too has to have a lifetime the same or greator than the service it's being injected to so this service is going to have to be a Singleton service.\nWe're going to have to inject it, well we're going to have to create it a reference to it in another way.\n\n## Step by step\n\n### Development (Localhost)\n\n- PlatformService runs on `5000` http and `5001` https locally\n- CommandsService runs on `6000` http and `6001` https locally\n\n### Production (K8s Cluster)\n\n1. `kubectl apply -f .\\platforms-depl.yml`\n2. `kubectl apply -f .\\platforms-np-srv.yml`\n3. `kubectl apply -f .\\commands-depl.yml`\n4. `kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/aws/deploy.yaml`\n5. `kubectl apply -f .\\ingress-srv.yml`\n6. `kubectl apply -f .\\local-pvc.yml`\n7. `kubectl apply -f .\\mssql-plat-depl.yml`\n8. `kubectl apply -f .\\rabbitmq-depl.yml`\n\n---\n\nChecking:\n\n1. `kubectl get deployments`\n2. `kubectl get pods`\n3. `kubectl get services`\n4. `kubectl get pvc`\n5. `kubectl get namespace`\n6. `kubectl get services --namespace=ingress-nginx`\n\n---\n\nUpdating Code:\n\n`platformservicedotnet` Or `commandservicedotnet`\n\n- `docker build -t dotpep/platformservicedotnet .`\n- `docker run -p 8080:80 dotpep/platformservicedotnet`\n- `docker push dotpep/platformservicedotnet`\n\n## Makefile\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotpep%2Fmicroservices-communication","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdotpep%2Fmicroservices-communication","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotpep%2Fmicroservices-communication/lists"}