Fazer um pedido envolve três serviços: o estoque reserva os itens, o pagamento autoriza o cartão e a expedição cria um envio. Num monólito, isso é uma única transação de banco de dados. Dividido em serviços com bancos próprios, não existe transação que abranja os três, e two-phase commit entre serviços raramente é uma opção na prática.
O padrão saga é a resposta clássica. Este artigo explica como uma saga funciona, a diferença entre orquestração e coreografia, como compensações e passos pivô se encaixam e os problemas de isolamento que as sagas não resolvem por você. O diagrama mostra uma saga de pedido orquestrada.
O que é uma saga
Uma saga é uma sequência de transações locais. Cada passo faz commit no banco do próprio serviço e dispara o seguinte. Se um passo falhar, a saga executa transações de compensação que desfazem os efeitos dos passos que já fizeram commit.
A ideia é mais antiga que os microsserviços: Hector Garcia-Molina e Kenneth Salem descreveram as sagas num artigo de 1987 sobre transações de banco de dados de longa duração. O padrão voltou porque as fronteiras entre serviços recriaram o mesmo problema.
Duas consequências moldam todo o resto:
- Consistência eventual. Entre o primeiro e o último passo, o sistema fica num estado intermediário que outras requisições conseguem ver. O pedido está em PENDING, o estoque está reservado e o cartão está autorizado, mas ainda não cobrado.
- Compensação não é rollback. Não dá para "desenviar" um e-mail nem desfazer uma cobrança em silêncio. Uma compensação é uma nova ação de negócio, como cancelar uma autorização ou emitir um reembolso, que reverte semanticamente a anterior.
Passos compensáveis, pivô e repetíveis
Classifique cada passo antes de desenhar qualquer coisa. O guia do padrão saga do Azure Architecture Center usa três tipos:
| Tipo | Significado | Exemplo |
|---|---|---|
| Compensável | Pode ser desfeito por outra transação | Reservar estoque; autorizar o pagamento |
| Pivô | O ponto sem volta: depois que dá certo, a saga precisa terminar | Criar o envio |
| Repetível | Vem depois do pivô e precisa dar certo em algum momento; idempotente | Enviar o e-mail de confirmação |
A ordem importa. Coloque primeiro os passos compensáveis, depois o pivô e, depois dele, só passos repetíveis. Se o pivô falhar, compense; depois que ele der certo, repita tudo o que vem a seguir até dar certo. Uma saga com um passo compensável depois do pivô não consegue chegar a um estado consistente quando esse passo falha.
Orquestração vs. coreografia
Há duas formas de coordenar os passos.
Orquestração: um orquestrador de saga, muitas vezes uma máquina de estados com estado durável, diz a cada serviço o que fazer e espera a resposta. Ele é dono da sequência, das novas tentativas, dos timeouts e das compensações.
Coreografia: não há coordenador. Cada serviço escuta eventos e reage: o estoque recebe OrderCreated e reserva os itens, o pagamento recebe StockReserved e autoriza, e assim por diante. Falhas também são eventos, e cada serviço sabe qual compensação executar.
| Orquestração | Coreografia | |
|---|---|---|
| Onde o fluxo vive | Num lugar só: o orquestrador | Espalhado pelos handlers de eventos dos serviços |
| Adicionar um passo | Mudar o orquestrador | Mudar quem escuta qual evento |
| Ver o estado de um pedido | Consultar o log da saga | Reconstruí-lo a partir dos eventos |
| Acoplamento | Os serviços conhecem os comandos do orquestrador | Os serviços conhecem os eventos uns dos outros |
| Bom para | Muitos passos, ramificações, ordem estrita | Dois ou três passos, fluxos simples |
A coreografia é agradável em fluxos curtos e penosa quando alguém pergunta "por que o pedido 8812 está travado?". A orquestração dá a essa pergunta um único lugar para olhar. Motores de workflow como Temporal, AWS Step Functions ou Camunda oferecem orquestração durável, para que você não precise construir a máquina de estados. A página de Chris Richardson sobre o padrão saga traz exemplos completos dos dois estilos.
Isolamento: a parte que as sagas deixam com você
Uma transação de banco de dados esconde o estado intermediário das outras transações. Uma saga, não. Enquanto uma saga de pedido roda, outra requisição pode ler o estoque reservado, ou uma segunda saga pode alterar o mesmo registro. As contramedidas comuns:
- Bloqueio semântico. Marque os registros como em andamento (um pedido em PENDING, estoque em RESERVED) para que outras operações saibam que devem esperar ou recusar.
- Atualizações comutativas. Projete as operações para dar o mesmo resultado em qualquer ordem, por exemplo incrementando e decrementando contadores em vez de definir o valor.
- Reler antes de escrever. Verifique se um valor não mudou desde que a saga o leu e, se mudou, falhe ou recomece.
Torne cada passo e cada compensação idempotentes, com o ID da saga e o passo como chave. Mensagens vão ser entregues duas vezes, e um "cancelar autorização" repetido não pode cancelar outro pagamento.
Timeouts e sagas travadas
Todo passo precisa de um prazo. Um serviço de pagamento que nunca responde deixa a saga esperando para sempre e o estoque reservado. Dê um timeout a cada passo, trate um timeout como falha antes do pivô (compense) e como motivo para repetir depois dele, e crie alertas para sagas que ficam num estado mais tempo do que o esperado. Um pequeno painel de sagas por passo atual responde sozinho à maioria das perguntas do suporte. Registre também por que cada saga terminou.
O diagrama de arquitetura
Conteúdo do diagrama
- Order service
- Saga orchestrator
- Saga log
- Inventory service
- Payment service
- Shipping service
- All steps succeeded?
- Order APPROVED
- Compensate in reverse order
- Order REJECTED
- start
- persist each step
- 1. reserve stock
- 2. authorize payment
- 3. create shipment
- yes
- no
- void, release
Como ler:
- Esquerda: o serviço de pedidos cria o pedido em PENDING e inicia a saga.
- Centro: o orquestrador executa os passos em ordem e persiste cada um no log da saga, para que uma reinicialização continue de onde parou.
- Direita: os três serviços, cada um rotulado com o número e o tipo do passo. Estoque e pagamento são compensáveis; a expedição é o pivô.
- Embaixo: se todos os passos derem certo, o pedido vira APPROVED. Se um passo antes do pivô falhar, o orquestrador compensa em ordem inversa (cancela a autorização e depois libera o estoque) e o pedido vira REJECTED.
- A tabela Markdown liga cada ação à sua compensação, que é a primeira coisa que quem revisa deveria checar.
O que colocar num diagrama de saga
- A ordem dos passos e o tipo de cada um. Compensável, pivô ou repetível vai na caixa.
- Cada compensação. Um passo sem compensação é o pivô, é repetível ou é um bug.
- Onde o estado da saga fica. Uma saga que não sobrevive a uma queda no meio do caminho não está pronta.
- Os estados intermediários visíveis. PENDING e RESERVED fazem parte do design; outras funcionalidades vão vê-los.
As sagas combinam naturalmente com o padrão transactional outbox, porque cada passo precisa atualizar o banco e enviar uma mensagem sem perder nenhum dos dois. O diagrama de arquitetura de microsserviços mostra onde esses serviços ficam, e o diagrama de integração com gateway de pagamento detalha os passos de autorização e captura.
Monte no Archboard
- Entre com Google ou GitHub e crie um diagrama.
- Adicione nós Contêiner do pack Modelo C4 para o serviço de pedidos, o orquestrador da saga e os três serviços participantes, e um Banco de dados para o log da saga.
- Coloque o número e o tipo do passo (compensável ou pivô) no campo de tecnologia de cada serviço.
- Adicione uma Decisão, um Processo e dois nós Início / Fim do pack Fluxograma para os caminhos de sucesso e de compensação.
- Adicione um bloco Markdown do pack Básico com uma tabela de ações e compensações.
O exemplo usa 11 nós de diagrama e fica dentro do plano Free.
Perguntas frequentes
Qual a diferença entre uma saga e uma transação distribuída? Uma transação distribuída (two-phase commit) bloqueia recursos em vários bancos até que todos façam commit. Uma saga faz commit de cada passo localmente e desfaz os passos anteriores com compensações se um posterior falhar, trocando isolamento por disponibilidade.
Devo usar orquestração ou coreografia? Orquestração para fluxos com muitos passos, ramificações ou ordem estrita, porque o estado de cada saga fica num lugar só. Coreografia para fluxos curtos em que dois ou três serviços reagem aos eventos uns dos outros.
O que é uma transação pivô? O passo depois do qual a saga não pode mais ser compensada. Tudo antes dele precisa ser compensável; tudo depois, repetível até dar certo.
Como lidar com falhas numa compensação? Repita. Compensações precisam ser idempotentes e dar certo em algum momento; se uma não conseguir, a saga precisa de um caminho de resolução manual e de um alerta.
As sagas me dão isolamento? Não. Outras requisições podem ver os estados intermediários. Use bloqueios semânticos como estados PENDING, atualizações comutativas e releituras para evitar as anomalias que importam para o seu negócio.