Marcio Cunha

Arquitetura de Transações Sagas Orquestradas com Compensações Assíncronas em Sistemas Financeiros

Descubra como construir transações distribuídas resilientes em sistemas financeiros usando Sagas orquestradas e compensações assíncronas para garantir consistência eventual sem travamento de bancos de dados.

Marcio Cunha•5 min
Também disponível em:EnglishEspañol
Resumo
  • Transações distribuídas em microsserviços financeiros exigem abandonar o bloqueio de banco em duas fases em favor da consistência eventual.
  • O padrão Saga orquestrado centraliza o fluxo de estado em um coordenador dedicado, evitando a dependência caótica de eventos dispersos.
  • Mensageria assíncrona desacopla os serviços participantes, permitindo que falhas momentâneas sejam absorvidas sem derrubar o motor de pagamentos.
  • Transações compensatórias revertem efeitos colaterais de forma lógica quando uma etapa falha após o débito inicial.
  • Idempotência rigorosa nas APIs impede cobranças duplicadas e corrompimentos de saldo durante novas tentativas de entrega de mensagens.

O desafio da consistência em sistemas financeiros distribuídos

Em sistemas financeiros modernos, a arquitetura de microsserviços substituiu os monólitos tradicionais. No entanto, dividir uma aplicação em vários serviços independentes traz um problema clássico: como garantir que uma transferência entre contas ocorra por completo ou não ocorra de jeito nenhum? Em um banco de dados monolítico, usamos transações que travam os registros até tudo terminar. Na nuvem, com bancos separados para cada serviço, essa trava global deixa de existir.

Quando um serviço de pagamento debita o saldo, mas o serviço de depósito falha ao creditar o valor na outra conta, o sistema fica em um estado inconsistente. Na prática, isso significa que o dinheiro sumiu da conta de origem sem chegar ao destino. Abordar esse problema exige abandonar as garantias tradicionais de bloqueio imediato e abraçar a consistência eventual, onde o sistema se ajusta e atinge o equilíbrio correto após alguns instantes.

O padrão Saga como alternativa ao bloqueio tradicional

Para resolver transações que cruzam múltiplos serviços sem travar o banco de dados inteiro, a engenharia de software utiliza o padrão Saga. Uma Saga é uma sequência de transações locais onde cada passo atualiza dados em um único serviço e publica um evento ou mensagem para disparar a etapa seguinte. Se todas as etapas terminam com sucesso, a operação é concluída. Se algo falha no meio do caminho, a Saga executa transações compensatórias para desfazer o que já foi feito.

Existem duas abordagens principais para implementar Sagas: a coreografada e a orquestrada. Na coreografada, cada serviço escuta eventos e decide por conta própria o que fazer a seguir, o que funciona bem em fluxos curtos, mas vira uma rede opaca de dependências em cenários complexos. Já na abordagem orquestrada, existe um componente central — o orquestrador — que conhece todo o fluxo de ponta a ponta e comanda cada serviço passo a passo, facilitando auditorias e o rastreamento de falhas.

O papel central do orquestrador de transações

O orquestrador funciona como o maestro de uma orquestra, ditando o ritmo e a ordem de execução dos serviços. Em vez de deixar que o serviço de cartões avise diretamente o serviço de milhas, o orquestrador recebe a solicitação inicial, chama o serviço de cartões, aguarda a resposta, valida o sucesso e só então comanda o serviço de milhas. Se o segundo passo falhar, o maestro sabe exatamente quem chamou e aciona a reversão na ordem inversa.

Na prática, esse componente central armazena o estado atual de cada transação em um banco de dados persistente. Se o próprio orquestrador cair no meio do processamento, ele reinicia, lê o estado anterior e continua exatamente de onde parou. Essa resiliência é indispensável em ambientes financeiros onde perder o rastro de uma operação equivale a perder dinheiro real.

Implementando compensações assíncronas para falhas

Em transações financeiras, desfazer uma operação nem sempre significa apenas fazer o oposto exato de forma simples. Se você debitou cem reais de uma conta e enviou para outra, a compensação exige creditar de volta os cem reais na conta original. No entanto, se o cliente já gastou o dinheiro ou se houve taxas envolvidas, a compensação ganha regras de negócio complexas que rodam de forma assíncrona via filas de mensagens.

O termo assíncrono significa que o sistema não espera a resposta imediata na mesma conexão HTTP. O orquestrador envia uma ordem de compensação para uma fila (como RabbitMQ ou Apache Kafka), libera o canal de atendimento e prossegue. Um worker especializado consome essa mensagem e executa o estorno em segundo plano, garantindo que falhas de rede temporárias não interrompam o processo de recuperação.

O exemplo abaixo ilustra uma estrutura básica em Python utilizando um modelo assíncrono para gerenciar o fluxo e disparar compensações em caso de falha:

import asyncio

async def debitar_conta(conta_id, valor):
    print(f"Debitando {valor} da conta {conta_id}")
    return True

async def estornar_conta(conta_id, valor):
    print(f"[COMPENSAÇAO] Estornando {valor} para a conta {conta_id}")
    return True

async def executar_saga(valor):
    sucesso_debito = await debitar_conta("A123", valor)
    if not sucesso_debito:
        print("Falha no débito. Abortando Saga.")
        return
    
    # Simulando falha no passo seguinte
    sucesso_credito = False
    if not sucesso_credito:
        print("Falha no crédito! Iniciando compensação assíncrona...")
        await estornar_conta("A123", valor)

asyncio.run(executar_saga(100))

Garantindo idempotência e tratamento de duplicatas

Sistemas baseados em filas e mensagens assíncronas enfrentam um problema inevitável: a entrega duplicada. Por causa de instabilidades na rede, uma mensagem de estorno ou pagamento pode ser enviada duas vezes para o mesmo serviço. Para evitar que o cliente receba o dobro do dinheiro ou seja cobrado em duplicata, cada operação deve ser idempotente, ou seja, executá-la múltiplas vezes produz exatamente o mesmo resultado que executá-la uma única vez.

Na prática, isso é resolvido exigindo um identificador único de transação (correlation ID ou idempotency key) em cada requisição. O serviço participante verifica em seu banco de dados se aquele identificador já foi processado. Se sim, ele apenas retorna o resultado anterior sem realizar a operação financeira novamente, blindando o sistema contra reentregas acidentais de mensagens.

Considerações finais sobre resiliência financeira

Construir arquiteturas financeiras baseadas em Sagas orquestradas com compensações assíncronas exige mudança de mentalidade, saindo da ilusão de transações imediatas para o controle rigoroso de estados e fluxos compensatórios. Embora adicione complexidade de desenvolvimento, o ganho em escalabilidade e isolamento de falhas compensa cada linha de código adicional.

Ao dominar o uso de orquestradores resilientes, filas de mensagens e chaves de idempotência, a engenharia garante que falhas de infraestrutura nunca se transformem em prejuízos financeiros reais para a instituição ou para os clientes.