Por que isso importa
Um cliente envia uma transação. O Midaz precisa fazer duas coisas: validá-la e persistir o resultado. No modo síncrono, ambos os passos rodam na mesma requisição. O cliente espera cada escrita chegar ao banco de dados antes de receber uma resposta. Esse modelo é simples e previsível, mas tem um teto. Em alto volume, 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. O Midaz valida a transação, devolve a resposta na hora e persiste os dados em segundo plano através do RabbitMQ. O cliente recebe respostas mais rápidas. Com o processamento assíncrono habilitado, o Bulk Recorder agrupa inserções por padrão; defina
BULK_RECORDER_ENABLED=false para persistir mensagens enfileiradas individualmente.
Para orientação mais ampla sobre escalabilidade, veja Estratégias de escalabilidade.
Como funciona
Modo síncrono (padrão)
O Midaz valida a transação e a escreve diretamente no PostgreSQL dentro do mesmo ciclo de requisição. A API envia sua resposta somente depois que cada operação de banco de dados se completa.Figura 1. Fluxo de transação síncrono — o cliente espera até que a gravação no banco de dados seja confirmada.
-
O cliente envia um
POST /transactionpara a API do Midaz. - A API valida a requisição — executa a validação da estrutura da requisição, as verificações de saldo e a aplicação de limites aqui.
- A API grava no PostgreSQL — persiste a transação e suas operações dentro do mesmo ciclo de requisição.
- O PostgreSQL confirma a gravação — faz commit de todos os registros.
-
A API retorna
201 Createdao cliente com a transação criada. A resposta sai do servidor somente depois que o banco de dados confirma tudo. A resposta carrega o status transitórioCREATED; o Midaz promove a transação paraAPPROVEDde forma assíncrona após o processamento de saldos. Não trate o201como aprovação final; espere o status chegar aAPPROVEDantes de considerar a transação liquidada.
- 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. A resposta mostra exatamente o que o Midaz persiste.
Mesmo no modo síncrono, o Midaz atualiza os saldos atomicamente no Redis durante a requisição. O Redis é a fonte autoritativa para os saldos. A gravação acima persiste a transação e suas operações, não as linhas de saldo no Postgres. O worker de sincronização de saldos, sempre ativo, reconcilia essas linhas (veja Sincronização de saldos).
Modo assíncrono
O Midaz valida a transação da mesma forma. Em vez de uma escrita direta 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.Figura 2. Fluxo de transação assíncrono — o cliente recebe uma resposta assim que a mensagem é publicada, e a persistência acontece em segundo plano.
-
O cliente envia um
POST /transactionpara a API do Midaz. - A API valida a requisição — executa a validação da estrutura da requisição, as verificações de saldo e a aplicação de limites exatamente como no modo síncrono.
- A API publica o payload da transação no RabbitMQ em vez de uma escrita direta no banco de dados.
-
A API retorna
201 Createdao cliente assim que a fila aceita a mensagem — o cliente não espera pela persistência no banco de dados. A resposta carrega o status transitórioCREATED; o Midaz promove a transação paraAPPROVEDde forma assíncrona após o processamento de saldos. Não trate o201como aprovação final; espere o status chegar aAPPROVEDantes de considerar a transação liquidada. - O RabbitMQ entrega a mensagem a um consumidor em segundo plano, desacoplado da requisição da API.
- O consumidor grava no PostgreSQL — persiste a transação e suas operações a partir da mensagem enfileirada. O worker de sincronização de saldos coordena as atualizações de saldo e mantém os saldos consistentes em ambos os modos (veja a seção Sincronização de saldos).
- 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.
- O Midaz serializa as mensagens com MessagePack para um transporte compacto e eficiente.
- Os consumidores em segundo plano escrevem no banco de dados no próprio ritmo, com retries; as inserções em lote exigem um Bulk Recorder habilitado.
Resiliência integrada
Se o RabbitMQ estiver indisponível quando o modo assíncrono tentar publicar uma mensagem, o Midaz tenta realizar uma escrita direta no banco de dados. Se essa escrita falhar, o Midaz retorna o erro do banco de dados. Isso significa:
- Durante uma indisponibilidade da fila, o Midaz tenta escrever diretamente no banco de dados.
- O cliente pode receber um erro se a escrita de fallback no banco de dados falhar.
- O Midaz registra a falha da fila e, se a escrita direta também falhar, a falha do fallback para que seu time de operações possa investigá-las.
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 e persistem diretamente no PostgreSQL. O bootstrap atual do Ledger ainda inicializa o RabbitMQ e conecta seu consumidor.
Com true, o ledger publica os payloads da transação no exchange configurado do RabbitMQ. Em seguida, 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
Um worker dedicado de sincronização de saldos coordena as atualizações de saldo. Ele utiliza o Redis como camada de coordenação. Esse worker roda tanto no modo síncrono quanto no assíncrono. Ele mantém os saldos consistentes mesmo quando múltiplos consumidores processam mensagens ao mesmo tempo.
O worker de sincronização de saldos roda automaticamente em ambos os modos. Você não precisa de configuração adicional além de uma instância do Redis disponível.
Circuit breaker do RabbitMQ
Quando você habilita o modo assíncrono, o Midaz depende do RabbitMQ para a persistência das transações. Um circuit breaker integrado protege contra indisponibilidades do broker. Ele monitora a saúde da conexão com o RabbitMQ e falha rápido quando o broker cai. Isso evita acúmulo de requisições e falhas em cascata. O circuit breaker está ativo no caminho RabbitMQ de tenant único. O RabbitMQ multi-tenant usa gerenciamento de conexões por tenant. O circuit breaker segue o modelo padrão de três estados:
- Fechado (normal): as requisições fluem normalmente para o RabbitMQ. O breaker contabiliza as falhas.
- Aberto (disparado): o breaker rejeita as requisições de imediato e não contata o RabbitMQ. Um health checker em segundo plano monitora o broker e tenta a recuperação.
- Semi-aberto (sondagem): o breaker deixa passar um número limitado de requisições para testar a recuperação do RabbitMQ. 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, o Midaz tenta realizar escritas diretas no banco de dados para transações assíncronas. Se uma escrita direta falhar, o Midaz retorna o erro do banco de dados; o fallback não garante a entrega da transação 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:
- O 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.
- O Bulk Recorder otimiza como o consumidor escreve essas mensagens no banco de dados — agrupa múltiplas mensagens em inserções em lote únicas.
BULK_RECORDER_ENABLED=false. Sem o modo assíncrono, a persistência de transações usa escritas diretas no banco de dados e não há fila de transações 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ê roda 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 de persistência de transações direta e vinculada à requisição.
- O volume de transações é baixo a moderado.
- Você quer que uma resposta de sucesso da API signifique que o Midaz já persistiu os dados.
- Você trabalha em um ambiente de desenvolvimento ou teste onde a simplicidade importa mais do que o throughput.

