Artigo
Padrão Saga: gerenciamento de transações distribuídas
Entenda o padrão Saga e como ele ajuda a gerenciar transações distribuídas em sistemas com múltiplos serviços.
- Publicado em
- Por
- Raphael Tavares · Engenheiro de software sênior
Relembrando Microsserviços
Para explicar este padrão arquitetural, primeiro precisamos pontuar uma característica da arquitetura de microsserviços, que é o fato de cada microsserviço ter seu próprio banco de dados.
Essa premissa existe por alguns motivos, entre eles o fato de que, se diferentes microsserviços compartilhassem o mesmo banco de dados, haveria um acoplamento indesejado e acabaríamos caindo no antipadrão conhecido como monólito distribuído.
Um possível problema causado por esse antipadrão é a gestão de mudança na estrutura de um banco de dados compartilhados por múltiplos times, onde é necessário envolver a revisão dos times para garantir que não haverá alteração em cada parte. Isso gera problemas de planejamento e burocracia, podendo ser evitado ao respeitar a regra de ouro dos microsserviços.
Acordamos então em manter um banco de dados para cada serviço, certo? Dessa forma, os bancos de dados serão uma camada abstraída por trás da API de seu serviço e somente a aplicação específica terá acesso a ele.
Por que precisamos do padrão Saga
Até então já temos um bom direcionamento para arquitetar nossa aplicação, mas ao adotar um banco de dados por serviço, surge um novo problema: Perdemos as propriedades ACID nas transações.
Relembrando rapidamente: uma transação é uma sequência de operações que, para um agente externo, deve parecer uma única ação.
E os príncipios ACID são: Atomicidade, Consistência, Isolamento e Durabilidade.
Quando usávamos um banco de dados unificado, podíamos contar com a funcionalidade de transação nativa do próprio banco para realizar múltiplas operações agrupadas em uma só.
No entanto, com um DB separado para cada serviço, como gerenciamos a consistência de dados através dos serviços em uma chamada “transação distribuída”?
A resposta: o padrão Saga.
No padrão Saga, os serviços executam operações que fazem parte de uma transação distribuída. Cada operação desencadeia a próxima, que provavelmente ocorrerá em outro microsserviço, gerando uma cascata de ações. Caso alguma dessas falhe, o padrão Saga é encarregado de instruir os serviços anteriores a aplicarem operações compensatórias, que terão o efeito inverso das operações originais, restaurando, assim, o banco de dados ao seu estado inicial.
Após a aplicação dessas compensações, dependendo da implementação, pode haver uma nova tentativa ou uma reversão completa, acompanhado de um retorno de erro.
Implementações
Podemos implementar o padrão Saga utilizando um de outros dois padrões arquiteturais:
- Padrão de orquestrador de execução
- Padrão de coreografia
No padrão de orquestrador de execução, temos um serviço orquestrador que gerencia todo o fluxo das transações distribuídas, chamando os serviços em ordem e esperando por suas respostas.
Dependendo da resposta de cada serviço, o orquestrador decide se deve prosseguir chamando o próximo, ou reverter a transação, chamando o serviço anterior mas para uma operação compensatória.
De forma similar, na implementação utilizando o padrão de coreografia temos um intermediador de mensagens ao invés de um serviço orquestrador e os serviços são inscritos nos eventos relevantes.
A diferença é que na ausência de um serviço orquestrador, os próprios serviços que participam da transação distribuída ficam encarregados de engatilhar a próxima operação, seja ela a próxima operação do caminho feliz ou a do caminho triste. Tudo isso através do envio de mensagens ao intermediador.
Com qualquer uma dessas estratégias, conseguimos realizar transações atomicamente envolvendo diversas aplicações e sem um banco de dados centralizado, resolvendo problemas de consistência e evitando erros no futuro.
Um exemplo palpável
Para terminarmos tendo uma noção prática de tudo que foi explicado, vamos a um exemplo prático. Na explicação passo a passo do fluxo ocultei os caminhos interrompidos de erro da imagem para não poluir o fluxograma, mas ainda os mencionarei.
Cenário
Temos um produto de venda de ingressos para eventos no geral, onde diversas organizações postam seus eventos e o usuário tem a possibilidade de comprar os ingressos. O usuário fará um pedido e faremos validações de segurança, cobrança e por fim reservaremos o ingresso, realizaremos a cobrança e enviaremos um e-mail para o cliente.

Fluxo
- O usuário compra um ingresso no site e o site envia uma requisição ao orquestrador.
- O orquestrador envia a requisição para o serviço de pedidos;
- Que salva o pedido como pendente;
- E envia a resposta de volta para o Orquestrador.
- caso a resposta seja de erro, o orquestrador retorna o erro para o usuário.
- O orquestrador chama o serviço de Segurança, para validar a identidade do cliente.
- O serviço valida os dados em seu banco de dados;
- E envia a resposta de volta para o Orquestrador.
- caso a resposta seja negativa ou de erro, o serviço de segurança avisa o orquestrador, que chama o serviço de pedido com a operação compensatória e depois retorna o erro para o usuário.
- O Orquestrador chama o serviço de Cobrança;
- Que chama o provedor de crédito do cliente e cria uma transação com status pendente.
- O serviço de Cobrança recebe a resposta de volta do provedor de crédito.
- Se a resposta for negativa ou erro, ele avisa o orquestrador, que reproduz os passos do número 7a.
- O serviço salva a cobrança como pendente no seu banco de dados;
- E envia a resposta de volta para o Orquestrador.
- O orquestrador chama o serviço de reserva;
- Que requisita a API do evento para reservar os assentos/ingressos de fato;
- E recebe a resposta.
- Caso a resposta seja negativa (as vezes o assento já foi comprado em outra plataforma) ou erro, o serviço de reserva devolve essa resposta para o orquestrador, que avisa o pedido de cobrança para cancelar a transação pendente e o serviço de pedido para cancelar o pedido pendente, além de retornar o cancelamento para o usuário.
- A reserva é então salva no banco de dados do serviço de reserva;
- E avisada ao orquestrador;
- Que então chama novamente o serviço de cobrança, para fazer a cobrança da transação que estava pendente;
- E o serviço de Pedido, para alterá-lo de “pendente” para “efetivado”.
- O orquestrador então chama o serviço de e-mail;
- Que envia um e-mail para o usuário;
- E retorna a resposta para o Orquestrador, finalizando o fluxo.
