Uma pessoa confirma uma compra. O serviço de pedidos cria o pedido, o serviço de pagamentos autoriza a cobrança e o serviço de estoque tenta reservar os produtos. A última etapa falha porque um item acabou.

Em um único banco, uma transação poderia executar um ROLLBACK e apagar todas as mudanças. Em serviços independentes, cada etapa já confirmou sua própria transação local. O pagamento não desaparece porque o estoque falhou.

O Saga Pattern organiza esse tipo de operação como uma sequência de transações locais. Quando o fluxo não pode continuar, ações de compensação levam o sistema a outro estado válido.

O que é Saga Pattern?

Saga é um padrão para manter a consistência de uma operação de negócio que atravessa vários serviços ou bancos de dados sem depender de uma única transação ACID distribuída.

Cada etapa da saga:

  1. Executa uma transação atômica dentro do limite de um serviço;
  2. Confirma a mudança no banco local;
  3. Dispara a próxima etapa por um comando, evento ou mensagem;
  4. Possui uma estratégia de falha: tentar novamente, compensar ou encaminhar para intervenção.
T1: criar pedido
        ↓
T2: autorizar pagamento
        ↓
T3: reservar estoque
        ↓
T4: confirmar pedido

Se T3 falhar de forma definitiva, a saga pode executar compensações na ordem inversa:

falha ao reservar estoque
        ↓
C2: cancelar autorização do pagamento
        ↓
C1: cancelar pedido

As compensações são novas operações de negócio. Elas não voltam no tempo nem apagam o histórico. Um pedido pode passar de PENDING para CANCELLED, e uma autorização pode ser estornada. Esses estados continuam disponíveis para auditoria.

Por que uma transação de banco não resolve?

Uma transação ACID funciona dentro do limite controlado pelo banco. Ela consegue confirmar todas as mudanças ou desfazê-las antes que se tornem visíveis.

Em uma arquitetura com banco por serviço, pedido, pagamento e estoque controlam dados diferentes:

Serviço de Pedidos   → banco de pedidos
Serviço de Pagamento → banco de pagamentos
Serviço de Estoque   → banco de estoque

Nenhum serviço pode simplesmente abrir uma transação local que inclua os outros bancos e uma API externa de pagamento. Protocolos como Two-Phase Commit coordenam participantes compatíveis, mas exigem suporte da infraestrutura, mantêm recursos presos durante a decisão e aumentam o acoplamento operacional. Também não transformam qualquer API externa em um recurso transacional.

A saga aceita que as confirmações aconteçam em momentos diferentes. Durante o fluxo, o sistema pode ficar temporariamente inconsistente: o pedido está pendente, o pagamento autorizado e o estoque ainda não reservado. A consistência é recuperada quando todas as etapas ou todas as compensações necessárias terminam.

Como funciona uma saga?

Uma saga precisa modelar o caminho feliz e as falhas esperadas.

Transações compensáveis

São etapas cujo efeito pode ser neutralizado por outra operação. Reservar estoque pode ser compensado por liberar a reserva. Autorizar uma cobrança pode ser compensado por cancelar a autorização.

Compensar não significa necessariamente restaurar exatamente o estado anterior. Se um e-mail já foi enviado, não é possível “desenviá-lo”; podemos registrar a correção e enviar outra mensagem. Se houve uma tarifa não reembolsável, a compensação pode exigir atendimento manual.

Ponto de não retorno

Alguns fluxos possuem uma etapa depois da qual voltar deixa de ser viável ou desejável. Essa etapa é chamada de pivot. Antes dela, etapas costumam ser compensáveis. Depois dela, o desenho deve favorecer operações repetíveis até a conclusão.

Em um pedido, capturar definitivamente o pagamento ou entregar o pacote à transportadora pode representar esse ponto, dependendo das regras do negócio.

Transações repetíveis

Depois do pivot, falhas transitórias normalmente exigem retry em vez de compensação. Essas etapas precisam ser idempotentes para que uma mensagem duplicada ou uma resposta perdida não repita o efeito.

compensáveis → pivot → repetíveis até concluir

Essa classificação não é automática. A equipe precisa conversar com produto, financeiro e operação para definir o que pode ser revertido, qual é o prazo da reversão e quais perdas são aceitáveis.

Coreografia

Na coreografia, não existe um controlador central do fluxo. Cada serviço reage a eventos e publica o resultado da sua transação local.

Pedido criado
      ↓
Pagamento autorizado
      ↓
Estoque reservado
      ↓
Pedido confirmado

Em caso de falha:

Reserva de estoque rejeitada
      ↓
Pagamento cancelado
      ↓
Pedido cancelado

Cada participante conhece apenas os eventos relevantes para sua responsabilidade. Isso reduz a necessidade de um componente coordenador e combina bem com fluxos curtos e orientados a eventos.

O custo aparece quando o processo cresce. A ordem fica espalhada entre consumidores, eventos podem formar ciclos e nenhum serviço possui sozinho a visão completa da saga. Entender “em que etapa está o pedido 842?” passa a depender de correlação, traces e histórico de mensagens.

Orquestração

Na orquestração, um componente mantém o estado do fluxo e envia comandos aos participantes.

                   ┌─ comando: autorizar pagamento ─→ Pagamento
                   │                                 ↓ resposta
Cliente → Orquestrador ─ comando: reservar estoque ─→ Estoque
                   │                                 ↓ resposta
                   └─ comando: confirmar pedido ────→ Pedidos

O orquestrador decide qual passo executar, interpreta a resposta e escolhe retry, compensação ou conclusão. Ele pode ser implementado como uma máquina de estados persistente ou por uma plataforma de workflows duráveis.

Centralizar a coordenação torna fluxos complexos mais explícitos, mas o orquestrador precisa sobreviver a reinícios, evitar executar passos duas vezes e não concentrar regras que pertencem aos domínios participantes. Ele coordena; o serviço de pagamentos continua responsável pelas regras de pagamento.

Coreografia ou orquestração?

AspectoCoreografiaOrquestração
CoordenaçãoDistribuída entre eventos e consumidoresExplícita em um orquestrador
Boa adequaçãoFluxos curtos e poucos participantesFluxos longos, ramificados ou com muitas compensações
VisibilidadeExige reconstruir o fluxo por telemetriaEstado central facilita acompanhar a execução
AcoplamentoServiços dependem de contratos de eventos

Participantes dependem de comandos; o orquestrador conhece o processo

EvoluçãoMuitos passos podem criar uma rede difícil de entenderO fluxo cresce em um ponto explícito, que pode ficar complexo
Falha de coordenaçãoNão há coordenador únicoO orquestrador precisa ser persistente e altamente disponível

Não existe uma escolha universal. Um fluxo de dois ou três eventos estáveis pode funcionar bem por coreografia. Um processo com prazos, caminhos alternativos, aprovação humana e várias compensações tende a ficar mais legível por orquestração.

Exemplo prático: processar um pedido

Considere uma saga orquestrada com quatro participantes:

  • Pedidos: registra o ciclo de vida da compra;
  • Pagamentos: autoriza ou cancela o valor;
  • Estoque: reserva ou libera os itens;
  • Entrega: cria ou cancela a solicitação de envio.

O fluxo de sucesso é:

1. Criar pedido como PENDING
2. Autorizar pagamento
3. Reservar estoque
4. Solicitar entrega
5. Marcar pedido como CONFIRMED

Uma tabela de estado da saga pode guardar:

saga_id:       saga-319
business_id:   order-842
current_step:  RESERVE_INVENTORY
status:        RUNNING
updated_at:    2026-10-01T14:30:00Z

Cada comando carrega saga_id, order_id e um identificador único da mensagem. Assim, participantes conseguem correlacionar o trabalho e deduplicar entregas repetidas.

Falha de negócio

Se o estoque responder OUT_OF_STOCK, tentar novamente não criará unidades. O orquestrador inicia compensações:

liberar estoque       → desnecessário, a reserva falhou
cancelar pagamento    → necessário, a autorização ocorreu
cancelar pedido       → necessário, o pedido foi criado

O resultado final não é “nada aconteceu”. É um pedido cancelado com histórico, uma autorização cancelada e nenhuma reserva ativa.

Falha transitória

Se o serviço de estoque não responder, o orquestrador ainda não sabe se a reserva aconteceu. Ele não deve interpretar timeout como rejeição.

Uma estratégia segura é:

  1. Repetir o comando com o mesmo identificador e backoff;
  2. Consultar o resultado conhecido daquela operação;
  3. Manter a saga em estado WAITING enquanto a resposta é incerta;
  4. Alertar ou encaminhar para reconciliação ao ultrapassar o prazo.

O serviço de estoque precisa tratar o comando de reserva de forma idempotente. Caso contrário, o retry pode reservar duas vezes.

Falha durante a compensação

Compensações também atravessam a rede e também falham. Se o cancelamento do pagamento estiver indisponível, a saga não deve se declarar cancelada como se tudo tivesse terminado.

status: COMPENSATING
step:   CANCEL_PAYMENT
retry:  4

O sistema continua tentando com uma política limitada e observável. Depois do limite automático, cria uma pendência operacional com contexto suficiente para reconciliação. Uma compensação nunca pode ser tratada como um bloco de código que sempre funciona.

Mensagens confiáveis e Outbox

Existe uma janela perigosa entre confirmar uma transação local e publicar a mensagem que inicia o próximo passo:

banco confirma mudança → processo cai → evento não é publicado

Se o serviço publicar primeiro, pode ocorrer o problema inverso: a mensagem é consumida, mas a mudança local falha.

O Transactional Outbox reduz essa lacuna ao salvar a mudança de negócio e a mensagem de saída na mesma transação local. Outro processo publica os registros pendentes no broker.

BEGIN
  atualizar pedido
  inserir evento na outbox
COMMIT

publicador → lê outbox → envia mensagem → marca como publicada

O publicador pode enviar a mesma mensagem mais de uma vez se cair antes de marcar o registro. Por isso, Outbox e idempotência se complementam: um reduz mensagens perdidas; a outra protege contra duplicatas.

Concorrência e falta de isolamento

Uma saga não oferece automaticamente o isolamento de uma transação ACID. Enquanto ela está em andamento, outras operações podem observar e modificar estados intermediários.

Imagine duas sagas disputando a última unidade de um produto ou uma alteração de endereço ocorrendo enquanto a entrega é criada. Podem surgir atualizações perdidas, leituras inconsistentes e decisões baseadas em dados que mudaram.

Algumas proteções possíveis são:

  • Estados explícitos, como PENDING, que impedem ações incompatíveis;
  • Controle otimista de concorrência com versão do registro;
  • Reservas com prazo em vez de decrementos definitivos antecipados;
  • Releitura e validação antes de uma etapa crítica;
  • Operações comutativas, quando a ordem não altera o resultado;
  • Reordenação do fluxo para adiar mudanças irreversíveis.

Essas proteções dependem da invariante de negócio. A saga coordena etapas, mas não substitui modelagem de concorrência.

Quando utilizar?

Considere Saga quando:

  • Uma operação de negócio atravessa serviços com dados próprios;
  • Não existe uma transação atômica comum entre os participantes;
  • Consistência eventual é aceitável por um período conhecido;
  • Cada etapa possui um resultado de negócio claro;
  • É possível definir compensações ou uma estratégia de conclusão por retry;
  • O custo operacional do fluxo distribuído é justificado.

Evite usar Saga apenas porque a arquitetura possui microsserviços. Se a operação cabe em um único limite transacional, uma transação local é mais simples e mais forte. Se duas partes precisam compartilhar invariantes atômicas o tempo todo, a divisão dos serviços pode estar errada.

Saga também não é adequada quando uma etapa irreversível ocorre cedo e não existe maneira aceitável de reparar uma falha posterior. Nesse caso, reorganize o processo, introduza aprovação ou reserva antes do efeito definitivo, ou reveja a experiência do produto.

Vantagens

  • Mantém cada transação dentro do serviço que controla os dados;
  • Evita manter locks distribuídos durante todo o processo de negócio;
  • Permite coordenar operações longas e participantes heterogêneos;
  • Torna falhas e compensações parte explícita do desenho;
  • Oferece caminhos para recuperação automática e reconciliação manual;
  • Funciona com coreografia ou orquestração conforme a complexidade do fluxo.

Limitações e trade-offs

DecisãoBenefícioCusto ou risco
Usar transações locaisAutonomia entre serviçosSem rollback automático do fluxo inteiro
Aceitar consistência eventualEvita coordenação síncrona globalEstados intermediários ficam visíveis
Compensar efeitosRecupera um estado válidoNem todo efeito pode ser realmente desfeito
CoreografarCoordenação descentralizadaFluxo e dependências ficam difíceis de rastrear
OrquestrarEstado e decisões explícitosCoordenador stateful exige alta confiabilidade
Fazer retrySupera falhas transitóriasDuplicatas sem idempotência e maior latência

Observabilidade e operação

Uma saga precisa ser rastreável por uma identidade estável. Registre pelo menos:

  • saga_id e identificador do negócio;
  • Estado atual, etapa e participante;
  • Comandos, eventos e identificadores das mensagens;
  • Número de tentativas e próximo retry;
  • Início, fim e duração de cada etapa;
  • Compensações pendentes ou falhas;
  • Motivo de falha sem expor dados sensíveis.

Métricas úteis incluem sagas concluídas, compensadas, presas e enviadas para intervenção; latência por etapa; idade da saga mais antiga; taxa de retry; e falhas de compensação.

Um trace distribuído ajuda a investigar uma execução, mas não deve ser a única fonte do estado operacional. O estado persistido da saga e o histórico de mensagens precisam permitir recuperação depois de reinícios e expiração dos traces.

Erros comuns

Chamar toda sequência de eventos de saga

Uma saga representa uma operação de negócio com conclusão, falhas e compensações definidas. Uma cadeia de eventos sem estratégia de recuperação é apenas uma cadeia de eventos.

Tratar compensação como rollback técnico

Compensação aplica uma nova regra de negócio. Ela pode ter custo, prazo, aprovação ou resultado parcial. Modele esses estados em vez de esconder tudo em um catch.

Compensar qualquer timeout imediatamente

Timeout significa resultado desconhecido, não falha confirmada. Antes de compensar, consulte, repita de forma idempotente ou reconcilie o efeito incerto.

Ignorar duplicatas e ordem das mensagens

Brokers e publicadores podem redeliver mensagens. Consumidores devem deduplicar efeitos e rejeitar transições inválidas ou antigas.

Publicar mensagem fora da transação local

Salvar a mudança e publicar separadamente cria uma janela de perda ou inconsistência. Use Outbox ou outra garantia equivalente quando a mensagem for necessária para o progresso da saga.

Criar um orquestrador onisciente

O orquestrador deve conhecer o fluxo, não reimplementar todas as regras dos participantes. Caso contrário, os serviços perdem autonomia e qualquer mudança de domínio exige alterar o coordenador.

Não preparar intervenção manual

Retries possuem limite e efeitos externos podem permanecer incertos. Operações críticas precisam de fila de pendências, contexto de auditoria e procedimentos de reconciliação.

Perguntas de entrevista

  1. Qual problema o Saga Pattern resolve e qual garantia ele não oferece?
  2. Qual é a diferença entre compensação e rollback de banco de dados?
  3. Quando você escolheria coreografia em vez de orquestração?
  4. Como tratar um timeout quando não sabemos se o participante concluiu a operação?
  5. Por que participantes e compensações precisam ser idempotentes?
  6. Como Outbox ajuda uma saga e por que ele não elimina duplicatas?
  7. Quais anomalias podem surgir pela falta de isolamento entre sagas concorrentes?
  8. O que deve acontecer quando uma compensação falha repetidamente?
  9. Como você acompanharia uma saga presa em produção?
  10. Quando a necessidade de muitas sagas pode indicar limites de serviço mal definidos?

Próximos conteúdos

Revise transações e ACID para comparar as garantias locais com uma operação distribuída. Em seguida, aprofunde idempotência, essencial para comandos e compensações repetidos com segurança.

Depois, estude Outbox Pattern, filas, retries com backoff e DLQ. Esses mecanismos não substituem a saga: eles tornam a entrega de mensagens e a recuperação do fluxo mais confiáveis.

Guarde este modelo mental:

quebrar a operação em transações locais
                ↓
definir sucesso, falha e compensação de cada etapa
                ↓
escolher coreografia ou orquestração
                ↓
garantir mensagens confiáveis e efeitos idempotentes
                ↓
observar, reconciliar e testar falhas

Referências