Por que isso importa
Quando um cliente envia uma transação, duas coisas precisam acontecer: validá-la e persistir os resultados. No modo síncrono, ambas ocorrem na mesma requisição — o cliente espera até que tudo seja escrito no banco de dados antes de receber uma resposta. Isso é simples e previsível, mas tem um teto. Em altos volumes, as escritas no banco de dados se tornam o gargalo. Cada transação segura uma conexão, espera por locks e concorre por I/O. O modo assíncrono quebra essa dependência. A transação é validada, a resposta é retornada imediatamente e a persistência acontece em segundo plano através do RabbitMQ. O cliente recebe respostas mais rápidas. O banco de dados recebe escritas em lotes controlados e otimizados. O sistema lida com mais usando menos. Para orientação mais ampla sobre escalabilidade, veja Estratégias de escalabilidade.
Como funciona
Modo síncrono (padrão)
A transação é validada e escrita diretamente no PostgreSQL dentro do mesmo ciclo de requisição. A resposta da API só é enviada depois que todas as operações de banco de dados forem concluídas.- O cliente envia um
POST /transactionpara a API do Midaz. - A API valida a requisição — parsing do DSL, verificações de saldo e aplicação de limites acontecem aqui.
- A API grava no PostgreSQL — a transação e suas operações são persistidas dentro do mesmo ciclo de requisição.
- O PostgreSQL confirma a gravação, sinalizando que todos os registros foram commitados.
- A API retorna
200 OKao cliente com a transação criada. A resposta só sai do servidor depois que o banco de dados confirmou tudo.
- O tempo de resposta inclui a latência de escrita no banco de dados.
- Cada transação é uma operação independente de banco de dados.
- Mais simples de raciocinar — o que você vê na resposta é o que está persistido.
Mesmo no modo síncrono, os saldos são atualizados atomicamente no Redis — que é a fonte autoritativa — durante a requisição; a gravação acima persiste a transação e suas operações, não as linhas de saldo no Postgres. Essas linhas são reconciliadas pelo worker de sincronização de saldos, sempre ativo (veja Sincronização de saldos).
Modo assíncrono
A transação é validada da mesma forma, mas em vez de escrever no banco de dados, o Midaz publica uma mensagem no RabbitMQ. Um consumidor em segundo plano pega a mensagem e trata a persistência separadamente.- O cliente envia um
POST /transactionpara a API do Midaz. - A API valida a requisição — parsing do DSL, verificações de saldo e aplicação de limites acontecem exatamente como no modo síncrono.
- A API publica o payload da transação no RabbitMQ em vez de gravar diretamente no banco de dados.
- A API retorna
200 OKao cliente imediatamente depois que a mensagem é aceita pela fila — o cliente não espera pela persistência no banco de dados. - O RabbitMQ entrega a mensagem a um consumidor em segundo plano, desacoplado da requisição da API.
- O consumidor grava no PostgreSQL — a transação e suas operações são persistidas a partir da mensagem enfileirada. As atualizações de saldo são coordenadas pelo worker dedicado de sincronização de saldos (veja a seção Sincronização de saldos), que mantém os saldos consistentes em ambos os modos.
- O tempo de resposta exclui a latência de escrita no banco de dados — o cliente só espera pela validação e pela publicação na fila.
- As mensagens são serializadas com MessagePack para um transporte compacto e eficiente.
- Os consumidores em segundo plano escrevem no banco de dados no próprio ritmo, com capacidades de batching e retries.
Resiliência integrada
Se o RabbitMQ estiver indisponível quando o modo assíncrono tentar publicar uma mensagem, o Midaz não falha a transação. Em vez disso, ele recorre automaticamente a uma escrita direta no banco de dados — o mesmo caminho do modo síncrono. Isso significa:
- Nenhuma transação é perdida por causa de uma indisponibilidade da fila.
- O cliente ainda recebe uma resposta de sucesso.
- O fallback é registrado em log para que seu time de operações possa investigar o problema da fila.
Habilitando o modo assíncrono
Configure uma variável de ambiente na aplicação do ledger:
false (o padrão), todas as transações usam processamento síncrono. Nenhum consumidor do RabbitMQ é necessário.
Quando definida como true, o ledger publica os payloads da transação no exchange configurado do RabbitMQ e um consumidor em segundo plano trata a persistência.
Configuração do RabbitMQ
O modo assíncrono utiliza as seguintes configurações do RabbitMQ (todas no
.env do ledger):
Sincronização de saldos
As atualizações de saldo são coordenadas através de um worker dedicado de sincronização que utiliza o Redis como camada de coordenação. Esse worker roda tanto no modo síncrono quanto no assíncrono e mantém os saldos consistentes mesmo quando múltiplos consumidores processam mensagens concorrentemente.
O worker de sincronização de saldos roda automaticamente tanto no modo síncrono quanto no assíncrono. Nenhuma configuração adicional é necessária além de ter o Redis disponível.
Circuit breaker do RabbitMQ
Quando o modo assíncrono está habilitado, o Midaz depende do RabbitMQ para a persistência das transações. Para proteger contra indisponibilidades do broker, o Midaz inclui um circuit breaker integrado que monitora a saúde da conexão com o RabbitMQ e falha rápido quando o broker está indisponível — evitando acúmulo de requisições e falhas em cascata. O circuit breaker está sempre ativo quando o RabbitMQ está em uso. Ele segue o modelo padrão de três estados:
- Fechado (normal): as requisições fluem normalmente para o RabbitMQ. As falhas são contabilizadas.
- Aberto (disparado): as requisições são rejeitadas imediatamente sem contatar o RabbitMQ. Um health checker em segundo plano monitora o broker e tenta a recuperação.
- Semi-aberto (sondagem): um número limitado de requisições é permitido para testar se o RabbitMQ se recuperou. Se tiverem sucesso, o circuito se fecha. Se falharem, ele reabre.
- O número de falhas consecutivas atinge o limite, OU
- A proporção de falhas excede o percentual configurado dentro da janela de contagem
Configuração do circuit breaker
Quando o circuito está aberto, as transações assíncronas fazem fallback para escritas síncronas diretas no banco de dados — a transação não é perdida. Esse fallback garante a integridade dos dados mesmo durante indisponibilidades do broker.
Como o modo assíncrono se conecta ao Bulk Recorder
O modo assíncrono e o Bulk Recorder são funcionalidades complementares que trabalham juntas:
- Modo assíncrono desacopla a resposta da API da persistência — as transações vão para o RabbitMQ em vez de diretamente para o PostgreSQL.
- Bulk Recorder otimiza como o consumidor escreve essas mensagens no banco de dados — agrupando múltiplas mensagens em inserções em lote únicas.
RABBITMQ_TRANSACTION_ASYNC=true E BULK_RECORDER_ENABLED=true). Sem o modo assíncrono, não há fila de mensagens — e sem fila, não há nada para agrupar.
Quando usar o modo assíncrono
Use o modo assíncrono quando:
- Você precisa de tempos de resposta de API mais baixos para a criação de transações.
- Sua carga de trabalho envolve altos volumes de transações (centenas+ por segundo).
- Você está rodando operações em lote como pagamentos em massa ou liquidações.
- Você quer desacoplar sua camada de API do desempenho do banco de dados.
- Você precisa da configuração mais simples possível (sem dependência do RabbitMQ).
- O volume de transações é baixo a moderado.
- Você quer a garantia de que uma resposta de sucesso da API significa que os dados já estão persistidos.
- Você está em um ambiente de desenvolvimento ou teste onde a simplicidade importa mais do que o throughput.

