ASP.NET Core & Microsserviços - Event Sourcing com Background Services e RabbitMQ

Num ambiente de Microsserviços é possivel aumentar a disponibilidade de suas aplicações ASP.NET Core com conceitos de programação reativa. Através de Event Sourcing com RabbitMQ e Background Services.

Este exemplo apresenta uma maneira eficaz de aumentar a capacidade de resposta e disponibilidade do sistema.

Microsserviços

Microsserviços é um estilo de arquitetura de sistemas. A base de microsserviço é desenvolver um único aplicativo como um conjunto de pequenos serviços independentes. Que são executados em seus próprios processos. Desenvolvidos e implantados de forma independente.

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms (…). These services are built around business capabilities and independently deployable by fully automated deployment machinery, (…) may be written in different programming languages and use different data storage technologies.

- Martin Fowler

Event Sourcing

Event sourcing é maneira de atualizar atomicamente o estado de uma entidade e publicar eventos. Um novo evento é criado toda vez que o estado de um objeto é alterado. Dessa forma é possivel reproduzir o estado atual de uma entidade através dos seus eventos.

Event Sourcing ensures that all changes to application state are stored as a sequence of events. Not just can we query these events, we can also use the event log to reconstruct past states, and as a foundation to automatically adjust the state to cope with retroactive changes. - Martin Fowler

Por quê Microsserviços e Event Sourcing juntos?

O objetivo ao escolher Microsserviços é criar sistemas com alta disponibilidade, utilizando o mínimo de recursos. O que significa fazer um uso melhor e mais eficiente dos recursos disponíveis e, em última análise, reduzir a quantidade de recursos necessária do sistema.

Criar aplicativos reativos. Conforme descrito no Reactive Manifesto. É uma maneira eficaz de utilizar os recursos disponíveis, aumentar a capacidade de resposta e disponibilidade do sistema em geral. Pois respondem a estímulos ao invés de esperar respostas das chamadas síncronas de request/response tradicionais.

É aqui que os eventos entram. São essenciais para sistemas reativos. Representam uma maneira eficaz de comunicação assíncrona entre Microsserviços. Podendo substituir modelos síncronos e tradicionais que fazem block da request, como o REST através do protocolo HTTP.

Como eventos representam o estado mais atualizado de uma entidade. Podem ser consumidos por diferentes Microsserviços de acordo com seu contexto.

Cenário

Um cenário clássico para introduzir a solução de Pedido e Pagamento. Dois serviços que juntos entregam um valor de negócio: Um pagamento. E são independentes entre sí:

  • Quando um novo pedido é efetuado, o serviço Pedido publica uma mensagem (PedidoEfetuadoEvent).
  • O Serviço Pagamento, inscrito na fila PedidoEfetuadoEvent recebe a mensagem e processa o pagamento

SHOW ME THE CODE

Esta solução utiliza o componente EasyNetQ para conectar no RabbitMQ e também introduzir o Background Services para manter uma conexão ativa com o Rabbit.

Código no GitHub

O projeto no GitHub utiliza um Frontend com ASP.NET Core MVC, um pouco diferente do tutorial abaixo, que utiliza um Console Application.

Pré-requisitos

Para esta demo é necessario possuir o RabbitMQ. Caso não tenha, utilize o RabbitMQ apartir do Docker.

docker run -d --hostname my-rabbit  --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Criando a solution

Crie uma Solution vazia chamada RabbitMQ-Example (File > New > Project > Other Project Types > Visual Studio Solutions).

Domain

Esse projeto contém as Models e Eventos utilizados pelas API's.

Adicione um projeto .NET Standard (Botão direito na Solution > Add > New Project > .NET Standard > Class Library (.NET Standard)

Adicione a referência do Newtonsoft.Json. (Botão direito no Projeto > Manage NuGet Packages > Browse)

Altere o conteúdo da Class1:

PS: Fique a vontade para separar uma classe por arquivo.

PedidoService

Adicione um novo projeto ASP.NET Core do tipo Api com o nome de PedidoService (Botão direito na Solution > Add > New Project > ASP.NET Core Web Application > API)


Adicione a seguinte referências do NuGet:

  • EasyNetQ

Adicione também a referência do projeto Domain. (Botao direito no projeto > Add > Reference > Selecione a Domain).

Remova o arquivo ValuesController. Adicione outra controller chamada PedidoController.cs.

Abra o arquivo launchSettings (Properties > launchSettings.json) e altere o applicationUrl para: "http://localhost:5000".

PagamentoService - Background Service + Subscribe

O serviço de Pagamento irá utilizar BackgroundServices do ASP.NET Core. Para manter um EventHandler ativo no segundo plano. Monitorando através do subscribe uma fila do RabbitMQ.

Adicione um novo projeto à solução. (Botão direito na Solution > Add > New Project > ASP.NET Core Web Application > API).

Apague o arquivo ValuesController (Controllers > ValuesController.cs).

Adicione a seguinte referência do NuGet:

  • EasyNetQ
  • CreditCardValidator

Adicione uma nova pasta chamada BackgroundServices e crie uma classe NovoPedidoEventHandler.cs. O código do serviço:

Para registrar o Background Service, vá até o Startup.cs e modifique o método ConfigureServices:

Desta forma, toda vez que a aplicação for inicializada, junto com ela irá subir o BackgroundService monitorando o RabbtMQ

Testando

Adicione ao projeto uma Console App chama TesteApp (File > New > .NET Core > Console App (.NET Core))

Adicione a seguinte referência do NuGet:

  • Refit

Adicione também a referência do Domain.

E escreva o seguinte código na class Program:

Rodando o projeto

Configure a solution para executar os projetos simultaneamente (Botao direito na Solution > Multiple startup projects)

Beneficios desta abordagem

O RabbitMQ vai garantir disponibilidade para sua aplicação. Se serviço de Pagamento apresentar instabilidade, as mensagens enviadas através do RabbitMQ ficarão guardadas até que ele se restabeleça. E também não afeta o serviço de Pedido.

Veja neste print o que acontece quando o serviço Pagamento não está disponivel. A fila guarda a mensagem para ser processada. Assim que aplicação subir o pagamento será processado:

Download

O projeto no GitHub utiliza um ASP.NET Razor MVC ao invés de um Console Application. Conferere no meu GitHub

Referências