Pular para o conteúdo principal

Transactional Outbox

Descrição​

O Transactional Outbox resolve o problema de atualizar o banco de dados de um serviço e, ao mesmo tempo, enviar uma mensagem ou evento a um message broker de forma atômica. Em vez de publicar diretamente no broker, o serviço grava a mensagem em uma tabela de "outbox" (ou em uma propriedade do próprio registro, em bancos NoSQL) dentro da mesma transação local que altera os dados de negócio.

Um componente separado, o message relay, lê as mensagens pendentes do outbox e as publica no broker. Como a gravação da mensagem e a alteração dos dados acontecem na mesma transação, a mensagem existe se, e somente se, a transação foi confirmada, e a ordem em que foi produzida é preservada.

A entrega do relay é "pelo menos uma vez": ele pode publicar a mesma mensagem mais de uma vez (por exemplo, se falhar após publicar e antes de marcar a mensagem como enviada). Por isso os consumidores precisam ser idempotentes.

Problemas que resolve​

  • Atualizar o banco e publicar no broker sem two-phase commit (2PC), que muitas vezes não é suportado ou é indesejável.
  • Evitar mensagens perdidas ou "fantasmas" quando a publicação ocorre dentro ou depois da transação e algo falha no meio.
  • Enviar a mensagem somente se a transação de banco for confirmada.
  • Preservar a ordem das mensagens, inclusive com várias instâncias atualizando o mesmo agregado.

Quando usar​

  • Sagas e eventos de domínio exigem que a mudança de estado e a publicação sejam consistentes.
  • O banco ou o broker não suportam transações distribuídas.
  • É necessário garantir que nenhum evento seja perdido nem emitido sem a respectiva alteração de dados.

Quando evitar​

  • O serviço usa Event Sourcing, em que o event store já cumpre o papel de log de eventos publicável.
  • A perda ocasional de mensagens é aceitável e a complexidade extra não se justifica.
  • Os consumidores não podem ser tornados idempotentes e duplicatas são inaceitáveis.

Trade-offs​

GanhoCusto / Risco
Atomicidade entre dados e mensagem sem 2PCNecessidade de um message relay e de uma tabela/estrutura extra
Ordem das mensagens preservadaPossibilidade de duplicatas exigindo consumidores idempotentes
Nenhuma mensagem perdida ou emitida sem commitFácil esquecer de gravar o evento ao alterar os dados
  • Consistência eventual: a mensagem chega ao broker com algum atraso após o commit.
  • Complexidade operacional: o relay deve ser monitorado, e o outbox precisa de limpeza periódica.
  • Acoplamento do esquema de mensagens ao banco do serviço.

Diagrama​

O serviço grava dados e mensagem na mesma transação; o relay lê o outbox e publica no broker, e o consumidor trata possíveis duplicatas.

Padrões relacionados​

  • Transaction Log Tailing — implementação do relay lendo o log de transações do banco
  • Polling Publisher — implementação do relay consultando periodicamente o outbox
  • Saga — gera a necessidade de enviar mensagens atomicamente com a atualização do banco
  • Event Sourcing — abordagem alternativa para publicar eventos de forma confiável
  • Idempotent Consumer — necessário para tolerar mensagens duplicadas do relay
  • Messaging — estilo de comunicação que usa o broker

Referência​