Padrão Outbox em Microsserviços com ASP.NET Core – Parte 1

Para começar, vou compartilhar sobre um padrão que eu aprendi a partir de alguns questionamentos próprios sobre como garantir a atomicidade de persistência de dados e envio de mensagens em um message broker. É um cenário muito comum uma arquitetura orientada a serviços/microsserviços!

Nesta primeira parte vou abordar o aspecto teórico, e no próximo artigo vou mostrar como implementá-lo com ASP.NET Core.

Vamos lá?


O problema

Não é querendo ser pessimista, mas eu curto pensar no estilo de “e se este componente da arquitetura falhar?” quando estou implementando uma aplicação. Um dos questionamentos que surgiu durante o desenvolvimento de serviços, e que envolviam publicação de mensagens em uma fila, é: e se por alguma razão a mensagem, após a persistência da entidade/agregado, falhar em ser publicada pela aplicação?

Neste cenário, utilizar uma transação distribuída entre um banco de dados e um message broker não é viável.

Eventos de domínio/integração são essenciais para o bom funcionamento de arquiteturas orientadas a evento. Imagina o cenário:

  • Usuário realiza um pedido no e-commerce;
  • O microsserviço Order processa a requisição, persistindo ao final o agregado Order em seu banco de dados;
  • Após persistir, vai publicar o evento OrderCreated, com os dados do pedido, para que outros microsserviços como Payment ou Warehouse trabalhem em cima dele e possam seguir o fluxo do negócio
  • Porém, a publicação da mensagem falha;
  • A requisição termina com o agregado Order persistido, mas sem os eventos publicados no message broker. Por conta disso, o fluxo está interrompido já que sem a mensagem os outros microsserviços não vão dar seguimento no processo.

Pensa bem nesse cenário. Como você vai tentar publicar novamente a mensagem? Parece simples, mas exige uma estrutura mínima para ser feito posteriormente. Afinal, o status do pedido já pode estar em WaitingForPayment ou WaitingForShipping. Em teoria, já deu “certo”. Não existe no negócio um status OrderCreatedPublishedToMessageBroker, correto?

Nesse cenário, o padrão Outbox surge como uma boa opção para garantir a consistência de dados.


Padrão Outbox

Também conhecido como Transactional Outbox, ele auxilia nesse cenário através de uso de uma tabela Outbox (pode nomear como quiser, foca no conceito).

Essa tabela teria como objetivo armazenar os dados da mensagem ou evento, e seus dados seriam armazenados ali como uma transação junto com a persistência da entidade/agregado do negócio.

Para fins didáticos, vou utilizar o termo job para representar um serviço que será executado em segundo plano, de forma recorrente. Em ASP.NET Core poderia ser um Hosted Service, por exemplo.

Após isso, um serviço/worker/job poderia então processar essas mensagens que estão na tabela Outbox, enviá-las ao message broker, e então atualizar seu status para confirmar o envio. Isso geralmente envolve o uso de uma coluna/campo PublishedAt, que seria nulo enquanto a mensagem não fosse processada por esse job.

Para facilitar o entendimento, criei um diagrama simples representando o padrão e situação descritos.

Diagrama do padrão Outbox

Como implementar

Um passo a passo para implementar esse padrão é:

  • Criar uma tabela Outbox, com os dados de mensagem/eventos;
  • Persistir mensagens/eventos de integração na tabela Outbox, e entidades/agregado de maneira transacional;
  • Implementar um job recorrente, que vai buscar os eventos que não foram publicados e publicá-los no message broker, e finalmente marcá-los como publicados na tabela Outbox.

No próximo artigo vou mostrar um exemplo de implementação desse padrão utilizando ASP.NET Core e RabbitMQ.


Se curtiu este artigo e tem interesse em alcançar o próximo nível em .NET, se destacando em sua equipe ou mercado, a lista de espera para o Método .NET Direto ao Ponto está recebendo inscrições. Inscreva-se aqui.

Esse curso tem mais de 150 vídeo-aulas e mais de 20 horas sobre temas como C#, ASP NET Core 5, EF Core, CQRS, Clean Architecture, Autenticação e autorização com JWT, Testes Unitários, além de mini-cursos em Microsserviços, Performance em .NET, ASP NET Core e Azure, Docker e ASP NET Core e AWS (em breve).


Para concluir, te desafio a:

  • Minimizar este artigo;
  • Abrir o bloco de notas ou mesmo pegar um caderno/folha;
  • Escrever o que entendeu do padrão Outbox;
  • Enviar um áudio para algum amigo da área explicando para ele.

Garanto que vai ajudar bastante na retenção do conhecimento obtido aqui.

Até o próximo artigo!