Pular para o conteúdo

apps/data-patterns/saga-pattern

090 · Dados & Persistência · ≈ 6 min de estudo

Saga Pattern (coreografia)

Quando uma operação atravessa serviços com bancos próprios, não existe BEGIN...COMMIT que cubra todos. A saga troca a atomicidade distribuída por uma sequência de transações locais, cada uma com uma compensação: se uma etapa falha, as anteriores são desfeitas por operações de negócio, que ficam no histórico. Aqui a saga é coreografada — nenhum coordenador; cada serviço reage ao evento do anterior no RabbitMQ.

passos
6
arquivos
9
teste
1
tecnologias
5
Infraestrutura realTypeScriptBunPostgreSQLRabbitMQDocker
Baixar cartão

Cenário

Banco digital paga boleto com o limite de crédito do cliente. Três serviços, cada um com seu schema: Pedidos registra o pagamento, Limites reserva e consome o limite, Pagamentos liquida o boleto na câmara. Se a câmara recusa depois de o limite ter sido reservado, a reserva precisa ser devolvida — sem transação distribuída.

Planta

Sequência
14/14
alt[limite insuficiente][reservado]alt[liquidado][recusado pela câmara]grava o pedido requested1boleto.payment.requested2reserva o limite3limit.rejected4pedido cancelled5limit.reserved6liquida o boleto7payment.settled8reserva vira limite usado9pedido completed10payment.declined11compensação: libera a reserva12limit.released13pedido cancelled14PedidosRabbitMQ boleto.sagaLimitesPagamentos
14

14 passos — reproduza para seguir o fluxo

Como funciona

6 passos

Coreografia ou orquestração com compensação.

Esconde cada passo: lembre antes de tocar para revelar.

  1. 01

    Pedidos grava o pedido antes de publicar boleto.payment.requested: a saga existe antes de alguém reagir

  2. 02

    Limites reserva sob FOR UPDATE; a reserva tem o saga_id como chave, e toda reentrega devolve o resultado gravado

  3. 03

    Pagamentos liquida por último, porque liquidação não tem compensação; o resultado também fica gravado por saga_id

  4. 04

    payment.declined dispara a compensação em Limites: libera a reserva (released), idempotente pelo status

  5. 05

    Compensação que não consegue rodar vai para boleto.saga.dlq — não há rollback do rollback, só alerta e ação manual

  6. 06

    O consumidor publica o evento seguinte com confirmação do broker e só então dá ack

Trade-offs

O que se ganha, o que se paga

3 vantagenscada ganho tem um preço3 custos

Vantagens

  • Sem coordenador nem lock distribuído

  • Cada serviço só conhece os eventos que consome

  • Serviço novo entra sem mudar os outros

Custos

  • Fluxo espalhado pelos handlers, difícil de enxergar

  • Janela de inconsistência até a compensação

  • Compensação que falha exige intervenção manual

apps/data-patterns/saga-pattern

9 arquivos

sql/

  • 01_schema.sqlschemaSchemas orders, limits e payments, um por serviço

src/

  • topology_saga.tsExchange, fila por serviço, DLX e DLQ, eventos
  • consumer_saga.tsConsumo: handler, publicação confirmada, ack ou DLQ
  • service_orders.tsInício da saga e fechamento do pedido
  • service_limits.tsReserva, compensação e consumo do limite
  • service_payments.tsLiquidação na câmara, etapa final
  • demo.tsdemoSagas concluída, rejeitada e compensada
  • saga_boleto.test.tstesteConclusão, rejeição, compensação, reentrega e DLQ contra PostgreSQL e RabbitMQ reais

src/config_saga.ts / src/

  • pool_saga.tsAmbiente validado, pool e transactionExecute

Executar · com Docker

  1. docker compose up -d --wait# sobe PostgreSQL · RabbitMQ
  2. bun install# dependências
  3. bun run demo# roda o cenário
  4. bun run test# integração contra o serviço real
Requisitos
BunDocker
Sobe junto
PostgreSQLRabbitMQ

Por que se relacionam

Teste rápido

Qual é o próximo passo depois de Saga Pattern?

Próximo projeto · Dados & PersistênciaTwo-Phase Commit (2PC)
Esc

↑ ↓ navegarEnter abrir191 resultados