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:
- Executa uma transação atômica dentro do limite de um serviço;
- Confirma a mudança no banco local;
- Dispara a próxima etapa por um comando, evento ou mensagem;
- 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?
| Aspecto | Coreografia | Orquestração |
|---|---|---|
| Coordenação | Distribuída entre eventos e consumidores | Explícita em um orquestrador |
| Boa adequação | Fluxos curtos e poucos participantes | Fluxos longos, ramificados ou com muitas compensações |
| Visibilidade | Exige reconstruir o fluxo por telemetria | Estado central facilita acompanhar a execução |
| Acoplamento | Serviços dependem de contratos de eventos | Participantes dependem de comandos; o orquestrador conhece o processo |
| Evolução | Muitos passos podem criar uma rede difícil de entender | O fluxo cresce em um ponto explícito, que pode ficar complexo |
| Falha de coordenação | Não há coordenador único | O 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 é:
- Repetir o comando com o mesmo identificador e backoff;
- Consultar o resultado conhecido daquela operação;
- Manter a saga em estado
WAITINGenquanto a resposta é incerta; - 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ão | Benefício | Custo ou risco |
|---|---|---|
| Usar transações locais | Autonomia entre serviços | Sem rollback automático do fluxo inteiro |
| Aceitar consistência eventual | Evita coordenação síncrona global | Estados intermediários ficam visíveis |
| Compensar efeitos | Recupera um estado válido | Nem todo efeito pode ser realmente desfeito |
| Coreografar | Coordenação descentralizada | Fluxo e dependências ficam difíceis de rastrear |
| Orquestrar | Estado e decisões explícitos | Coordenador stateful exige alta confiabilidade |
| Fazer retry | Supera falhas transitórias | Duplicatas 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_ide 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
- Qual problema o Saga Pattern resolve e qual garantia ele não oferece?
- Qual é a diferença entre compensação e rollback de banco de dados?
- Quando você escolheria coreografia em vez de orquestração?
- Como tratar um timeout quando não sabemos se o participante concluiu a operação?
- Por que participantes e compensações precisam ser idempotentes?
- Como Outbox ajuda uma saga e por que ele não elimina duplicatas?
- Quais anomalias podem surgir pela falta de isolamento entre sagas concorrentes?
- O que deve acontecer quando uma compensação falha repetidamente?
- Como você acompanharia uma saga presa em produção?
- 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