Comunicação assíncrona entre microsserviços com RabbitMQ
As aplicações baseadas no DevPrime incorporam nativamente uma abordagem de arquitetura dirigida por eventos (Event-Driven Architecture). Elas recebem eventos externos, processam regras de negócio, emitem eventos internos e, quando necessário, propagam os eventos externamente utilizando o adaptador Stream, que se conecta nativamente com RabbitMQ, Kafka e outras plataformas.
Agora, montaremos uma demonstração envolvendo dois microsserviços. O primeiro, “Order”, receberá pedidos, enquanto o segundo, “Payment”, processará os pagamentos. No exemplo, utilizaremos dois containers criados no Docker. É fundamental subir os containers MongoDB e RabbitMQ.
Se você já possui os serviços MongoDB e RabbitMQ localmente, altere as configurações no arquivo /src/App/app/appsettings.json, nas seções State e Stream, com suas credenciais.
Cheklist e preperação do ambiente inicial:
- Abra uma conta na plataforma Devprime e adquira uma licença (Developer/Enterprise).
- Instale uma versão atualizada do .NET (Linux, macOS e Windows)
- Instale e/ou atualize o Visual Studio Code e/ou o Visual Studio 2023 Community / Professional / Enterprise.
- Instale e/ou atualize o Docker (Para Windows, utilize o WSL2).
- Inicialize os containers do MongoDB e RabbitMQ no Docker e adicione a fila ‘orderevents’ e “paymentevents” no RabbitMQ.
- Instale e ative a versão mais nova do Devprime CLI.
- Crie uma pasta para os seus projetos e defina as permissões de leitura e gravação.
- Consulte o artigo “Criando o primeiro microsserviço” para explorar os primeiros passos na Devprime.
Código-fonte de exemplo com os microsserviços Order e Payment
Este artigo implementará o código de exemplo abaixo para todos os assinantes da plataforma Devprime. Você não precisa baixá-lo e pode seguir na implementação nos próximos tópicos.
|
|
Importante: Caso tenha baixado o projeto, é necessário executar o comando dp stack
na pasta clonada para atualizar a sua licença Devprime nos projetos.
|
|
Criando o primeiro microsserviço “Order”
Utilizaremos o DevPrime CLI para a criação dos microsserviços. Neste exemplo, informaremos o nome da nova aplicação, o tipo de serviço de Stream como “RabbitMQ” para emissão de eventos assíncronos e o State como “MongoDB” para a persistência dos dados. Para iniciar um novo microsserviço, utilize o comando de exemplo apresentado. Uma nova aplicação será criada em segundos e estará pronta para produção.
dp new Order --stream rabbitmq --state mongodb
Adicionando uma regra de negócio de pedidos via Devprime Marketplace
dp marketplace order
Executando acelerador para implementação de código baseado o Domain. Ao executar o comando a primeira vez nessa demonstração digite “A” para que possa avançar e realizar as alterações.
dp init
O acelerador implementa automaticamente as classes de “Domain Events” em Domain, “Event Handlers” em Application, “Domain Services” em Application, “Application Services” em Application, a persistência em State, as APIs em Web e alguns testes unitários em Tests como exemplo.
Ao executar a aplicação novamente utilizando o script “.\run.ps1” (Windows) ou “.\run.sh” (Linux/macOS) nós já teremos uma nova visualização da sua API. Abra o browser web na url http://localhost:5000 e localize no Swagger o método post e clique em “Try it out".
Preencha dos dados do JSON para depois clicar em “execute”. Retorne ao prompt de commando acompanhe o resultado no log do microsserviço gerado automaticamente pelo adapter de Observability do Devprime.
Para conferir um exemplo de código implementado pelo acelerador acompanhe o código na pasta src/Core/Application/EventHandlers/Order/OrderCreatedEventHandler.cs que notifica via adapter de Stream.
code src/Core/Application/EventHandlers/Order/CreateOrderEventHandler.cs
|
|
Neste momento, o log demonstra o recebimento de uma requisição HTTP na API “Order”, que a repassa para o serviço de aplicação. Em seguida, a regra de negócio no domínio é processada, emitindo o evento “OrderCreated”. Esse evento tem seu estado persistido no MongoDB e resulta em uma notificação no mundo externo pelo Stream.
Ao acessar o RabbitMQ pelo portal, é possível observar este evento na fila “OrderEvents”. Isso significa que o microsserviço “Order” já cumpriu seu papel e notificou esse fato de negócio para que possa ser percebido por outro serviço.
Como a comunicação neste exemplo é totalmente assíncrona, os eventos na fila do RabbitMQ serão lidos pelo microsserviço “Payment” conforme configurado. Você pode parar a aplicação pressionando “Control” + “C” a qualquer momento e carregá-la novamente quando desejar.
Parabéns !!! Você já tem o microsserviço “Order”
Criando o segundo microsserviço “Payment”
O segundo microsserviço será chamado “Payment”, e iniciaremos sua criação neste momento. Durante a implementação, um item adicional que configuraremos será a ativação do “subscribe” no adaptador de Stream, permitindo que o microsserviço “Payment” receba os eventos emitidos pelo microsserviço “Order”.
Executando o dp new e criando o microsserviços
dp new ms-payment --state mongodb --stream rabbitmq
Adicionando uma regra de negócio de pagamento via Devprime Marketplace
dp marketplace payment
Executando o comando “dp init” da Devprime para implementação de código baseado em Domain-Driven Design (DDD).
dp init
Para executar os dois microsserviços no mesmo ambiente local, é necessário alterar a porta HTTP do microsserviço “Payment”. Na pasta do projeto “ms-payment”, edite o arquivo src/App/appsettings.json, na chave “web”, alterando para 5002 e 5003, conforme o exemplo abaixo:
|
|
Execute a aplicação utilizando o comando abaixo
.\run.ps1 ou ./run.sh (Linux, MacOS)
Se a aplicação rodou está correndo tudo bem. Feche a mesma com “Control+C” e seguimeremos com as implamentações para habilitar o recebimento dos eventos emitidos pelo microsserviços “Order”.
O próximo passo é adicionar a configuração no serviço de Stream e criação de um DTO para recebermos os dados do evento. Você pode fazer todo o processo manualmente ou utilizando o acelerador abaixo.
dp add subscribe OrderCreated -as PaymentService
Ao confirmar a alteração você terá três arquivos modificados para que possamos avançar nas configurações.
|
|
Abra o arquivo OrderCreatedEventDTO.cs
e adicione as seguintes propriedades:
Visual Studio Code
code src/Core/Application/Services/Payment/Model/OrderCreatedEventDTO.cs
|
|
Agora, edite o arquivo “EventStream.cs” configurando as propriedades definidas no “OrderCreatedEventDTO”. Modificaremos o serviço de aplicação para utilizar o método “Add”. Essa implementação indica que estaremos realizando um “Subscribe” no evento chamado “OrderCreated”, que será vinculado ao alias “Stream1” no adaptador Stream.
code src/Adapters/Stream/EventStream.cs
|
|
A etapa final é alterar o arquivo de configuração do adaptador de Stream no arquivo src/App/appsettings.json
e adicionar o nome da fila / tópico “orderevents” em “subscribe”, conforme exemplo abaixo:
|
|
Parabéns! Você já tem o microsserviço “Payment” configurado para fazer subscribe na fila/tópico chamado “OrderEvents”.
Comunicação assíncrona entre os microsserviços
Agora você chegou ao grande momento de executar os dois microsserviços. Abra cada um em uma janela e execute para que ambos tenham os serviços ativos. Acesse a URL do microsserviço “Order” em http://localhost:5000 e depois vá em “Post” e clique no botão “Try it out”. Realize um post e acompanhe o incrível resultado, com o detalhamento completo em cada microsserviço e o “Payment” reagindo ao evento recebido.
Neste momento, estamos verificando o resultado do processamento no microsserviço “Order”, que recebe um POST e emite o evento “OrderCreated”. Todos os detalhes são gerados automaticamente pelo adaptador de Observabilidade do Devprime.
[INF][Web]["https://localhost:5001;http://localhost:5000"][Host]["Production"][Parameters]["Appsettings"][RequestId: 3282e6f8-d2bd-4ccf-934a-546276a83038]
[2021-06-19T20:23:07.654-03:00][INF][Web]["HTTP"][Order][Add]["{\n \"customerName\": \"Ramon\",\n \"customerTaxID\": \"string\",\n \"itens\": [\n {\n \"description\": \"string\",\n \"amount\": 0,\n \"sku\": \"string\",\n \"price\": 0\n }\n ],\n \"total\": 0\n}"][Origin:"https://localhost:5001/swagger/index.html"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Application][OrderService][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Domain][Order][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Domain][Order][Handle][Event]["OrderCreated"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Application][EventHandler]["OrderCreatedEventHandler"][Event]["OrderCreated"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][State][Type "MongoDB"][Alias "State1"][OrderRepository][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Stream][Type "RabbitMQ"][Alias "Stream1"][Out][Event]["OrderCreated"]["Delivered"]["OrderEvents"]["{\"SagaId\":\"00000000-0000-0000-0000-000000000000\",\"Id\":\"35bc8937-deb8-4e35-a8c4-003171fd6e1b\",\"CorrelationId\":\"06721dfc-fd50-4783-8ea7-df201c22599b\",\"AppId\":\"3282e6f8-d2bd-4ccf-934a-546276a83038\",\"AppName\":\"ms-order\",\"Version\":1,\"Name\":\"OrderCreated\",\"When\":\"2021-06-19T20:23:07.8540357-03:00\",\"Payload\":{\"CustomerName\":\"Ramon\",\"CustomerTaxID\":\"string\",\"Total\":0,\"ID\":\"55a72f16-f4e5-476b-85d9-e86c6e6f390c\"}}"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
E agora o momento que chega o evento ‘OrderCreated’ no microsserviços “Payment”.
[INF][Web]["https://localhost:5003;http://localhost:5002"][Host]["Production"][Parameters]["Appsettings"][RequestId: 072b12e7-c941-4b4b-9823-cbd6e4425309]
[INF][Stream][Type "RabbitMQ"][Alias "Stream1"][In][Event]["OrderCreated"]["OrderEvents"]["{\"SagaId\":\"00000000-0000-0000-0000-000000000000\",\"Id\":\"35bc8937-deb8-4e35-a8c4-003171fd6e1b\",\"CorrelationId\":\"06721dfc-fd50-4783-8ea7-df201c22599b\",\"AppId\":\"3282e6f8-d2bd-4ccf-934a-546276a83038\",\"AppName\":\"ms-order\",\"Version\":1,\"Name\":\"OrderCreated\",\"When\":\"2021-06-19T20:23:07.8540357-03:00\",\"Payload\":{\"CustomerName\":\"Ramon\",\"CustomerTaxID\":\"string\",\"Total\":0,\"ID\":\"55a72f16-f4e5-476b-85d9-e86c6e6f390c\"}}"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Application][PaymentService][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Domain][Payment][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Domain][Payment][Handle][Event]["PaymentCreated"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Application][EventHandler]["PaymentCreatedEventHandler"][Event]["PaymentCreated"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][State][Type "MongoDB"][Alias "State1"][PaymentRepository][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
Parabéns! 🚀 Você acabou de desenvolver dois microsserviços utilizando Event-Driven com a plataforma Devprime e o Stream do RabbitMQ.
Para saber mais:
Última modificação September 12, 2024 (cac3c638)