> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Processamento assíncrono de transações

> O processamento assíncrono de transações valida a chamada rapidamente e então persiste a gravação através do RabbitMQ, para menor latência de API e maior throughput.

## Quando as gravações síncronas se tornam o gargalo

***

Um cliente envia uma transação. O Midaz deve fazer duas coisas: validá-la e persistir o resultado. No modo síncrono, as duas etapas rodam na mesma requisição.

Esse modelo é simples e previsível, mas tem um teto. Em alto volume, as gravações no banco de dados se tornam o gargalo. Cada transação ocupa uma conexão, espera por locks e disputa I/O.

O modo assíncrono rompe essa dependência. O Midaz valida a transação, retorna a resposta de imediato e persiste os dados em segundo plano através do RabbitMQ. O cliente recebe respostas mais rápidas.

Para orientações mais amplas de escalabilidade, veja [Estratégias de escalabilidade](https://docs.lerian.studio/pt/products/midaz/scalability-strategies.md).

## Como funciona

***

### Modo síncrono (padrão)

![Diagrama de sequência mostrando o cliente enviando um POST /transaction para a API do Midaz, que a valida, grava a transação e as operações no PostgreSQL e retorna 201 Created ao cliente.](https://mintcdn.com/lerian-49cb71fc/TGLv2g3qhXqf0dqb/images/pt/d2/sync-transaction-flow.svg?fit=max\&auto=format\&n=TGLv2g3qhXqf0dqb\&q=85\&s=da4f152afedd028f1ed4945688ef5d6d)

Figura 1. Fluxo de transação síncrono.

O fluxo completo tem estas etapas:

1. **O cliente envia** um `POST /transaction` para a API do Midaz.

2. **A API valida a requisição.** Ela executa aqui a validação do formato da requisição, as checagens de saldo e a aplicação de limites.

3. **A API grava no PostgreSQL.** Ela persiste a transação e as operações dela no mesmo ciclo de requisição.

4. **A API retorna `201 Created`** ao cliente com a transação criada. A resposta carrega o status `CREATED`, e o Midaz armazena a transação como `APPROVED`. Um `201` significa que o Midaz aplicou a transação aos saldos.

**Características:**

* O tempo de resposta inclui a latência de gravação no banco de dados.
* Cada transação é uma operação independente no banco de dados.
* Mais simples de entender.

> [!NOTE]
>
> Mesmo no modo síncrono, o Midaz atualiza os saldos de forma atômica no Redis durante a requisição. O Redis é a fonte de verdade para saldos. A gravação acima persiste a transação e as operações dela, não as linhas de saldo do Postgres. O worker de sincronização de saldo, que roda continuamente, reconcilia essas linhas (veja [Sincronização de saldo](#balance-synchronization)).

### Modo assíncrono

O Midaz valida a transação da mesma forma. Em vez de uma gravação 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.

![Diagrama de sequência mostrando o cliente enviando um POST /transaction para a API do Midaz, que a valida, publica o payload no RabbitMQ e retorna imediatamente 201 Created ao cliente. Em paralelo, o RabbitMQ entrega a mensagem a um consumidor em segundo plano, que grava a transação e as operações no PostgreSQL; os saldos são tratados pelo worker dedicado de sincronização de saldo.](https://mintcdn.com/lerian-49cb71fc/vdBt8wfgjsNRO1rf/images/pt/d2/async-transaction-flow.svg?fit=max\&auto=format\&n=vdBt8wfgjsNRO1rf\&q=85\&s=0a7b249ea617df59677f5bcefb7632b7)

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 fluxo completo tem estas etapas:

1. **O cliente envia** um `POST /transaction` para a API do Midaz.

2. **A API valida a requisição.** Ela executa a validação do formato da requisição, as checagens de saldo e a aplicação de limites exatamente como no modo síncrono.

3. **A API publica o payload da transação no RabbitMQ** em vez de gravar diretamente no banco de dados.

4. **A API retorna `201 Created`** ao 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 `CREATED`, e o Midaz armazena a transação como `APPROVED`. Um `201` significa que o Midaz aplicou a transação aos saldos.

5. **O RabbitMQ entrega a mensagem** a um consumidor em segundo plano, desacoplado da requisição da API.

6. **O consumidor grava no PostgreSQL.** Ele persiste a transação e as operações dela a partir da mensagem enfileirada. O worker de sincronização de saldo copia os saldos para o PostgreSQL em ambos os modos (veja a seção **Sincronização de saldo**).

**Características:**

* O tempo de resposta exclui a latência de gravação no banco de dados.
* As consultas de lista mostram uma transação nova depois que o consumidor a grava.
* Os consumidores em segundo plano gravam no banco de dados no próprio ritmo, com novas tentativas. As inserções em lote exigem o Bulk Recorder habilitado.

> [!TIP]
>
> A etapa de validação é idêntica nos dois modos. As checagens de saldo, a validação do formato da requisição e a aplicação de limites acontecem antes de a API responder, independentemente do modo de processamento. A diferença está apenas em *quando* os dados chegam ao banco de dados.

## Resiliência embutida

***

Se a publicação no RabbitMQ falhar no modo assíncrono, o Midaz grava a transação no banco de dados durante a requisição. Se essa gravação também falhar, a transação continua aplicada aos saldos. O Midaz mantém o registro da transação e tenta a gravação de novo em segundo plano. O modo síncrono usa a mesma recuperação quando a gravação dele no banco de dados falha.

Isso significa:

* Durante uma indisponibilidade da fila, o Midaz grava diretamente no banco de dados.
* Uma gravação com falha no banco de dados não rejeita uma transação que o Midaz já aplicou aos saldos.
* O Midaz registra em log a falha da fila e a gravação adiada, para que a sua equipe de operações possa investigá-las.

> [!WARNING]
>
> Durante uma indisponibilidade da fila, a latência pode aumentar porque as gravações vão direto para o banco de dados. Monitore a saúde do seu RabbitMQ para manter o modo assíncrono ativo.

## Habilitando o modo assíncrono

***

Defina uma variável de ambiente na aplicação do ledger:

```bash Environment variable theme={null}
RABBITMQ_TRANSACTION_ASYNC=true
```

Com `false` (o padrão), todas as transações usam o processamento síncrono e persistem diretamente no PostgreSQL. O ledger ainda se conecta ao RabbitMQ e roda o consumidor dele nesse modo.

Com `true`, o ledger publica os payloads de transação no exchange do RabbitMQ configurado. Um consumidor em segundo plano então trata a persistência.

## Configuração do RabbitMQ

***

O modo assíncrono usa as seguintes configurações do RabbitMQ (todas no `.env` do ledger):

| Variável | Descrição | Valor de exemplo |
| :- | :- | :- |
| `RABBITMQ_TRANSACTION_ASYNC` | Habilita o processamento assíncrono. | `false` |
| `RABBITMQ_HOST` | Hostname do servidor RabbitMQ. | `midaz-rabbitmq` |
| `RABBITMQ_PORT_HOST` | Porta do protocolo AMQP. | `3003` |
| `RABBITMQ_PORT_AMQP` | Porta da API de gerenciamento. | `3004` |
| `RABBITMQ_DEFAULT_USER` | Credenciais do produtor (usuário). | `transaction` |
| `RABBITMQ_DEFAULT_PASS` | Credenciais do produtor (senha). | — |
| `RABBITMQ_CONSUMER_USER` | Credenciais do consumidor (usuário). | `consumer` |
| `RABBITMQ_CONSUMER_PASS` | Credenciais do consumidor (senha). | — |
| `RABBITMQ_NUMBERS_OF_WORKERS` | Número de goroutines de worker do consumidor. | `5` |
| `RABBITMQ_NUMBERS_OF_PREFETCH` | Mensagens pré-buscadas por worker. | `10` |
| `RABBITMQ_TRANSACTION_BALANCE_OPERATION_EXCHANGE` | Nome do exchange para mensagens de transação. | `transaction.transaction_balance_operation.exchange` |
| `RABBITMQ_TRANSACTION_BALANCE_OPERATION_KEY` | Chave de roteamento. | `transaction.transaction_balance_operation.key` |
| `RABBITMQ_TRANSACTION_BALANCE_OPERATION_QUEUE` | Nome da fila. | `transaction.transaction_balance_operation.queue` |

> [!TIP]
>
> O consumidor usa credenciais separadas (`RABBITMQ_CONSUMER_USER` / `RABBITMQ_CONSUMER_PASS`) das do produtor. O consumidor republica as mensagens que ele tenta de novo, então ele também precisa de acesso de escrita ao exchange de transações.

## Sincronização de saldo

***

Um worker dedicado de sincronização de saldo copia os saldos do Redis para o PostgreSQL. Esse worker roda tanto no modo síncrono quanto no assíncrono.

| Variável | Descrição | Padrão |
| :- | :- | :- |
| `BALANCE_SYNC_BATCH_SIZE` | Número de atualizações de saldo agrupadas antes do flush. | `50` |
| `BALANCE_SYNC_FLUSH_TIMEOUT_MS` | Tempo máximo de espera (ms) antes do flush de um lote incompleto. | `500` |
| `BALANCE_SYNC_POLL_INTERVAL_MS` | Com que frequência (ms) o worker verifica atualizações pendentes. | `50` |

O worker de sincronização de saldo roda automaticamente nos dois modos. Você não precisa de nenhuma configuração extra além de uma instância do Redis disponível.

## Circuit breaker do RabbitMQ

***

Um circuit breaker embutido protege as publicações no RabbitMQ de mensagens de auditoria e eventos de overdraft. 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.

### Configuração do circuit breaker

| Variável | Descrição | Padrão |
| :- | :- | :- |
| `RABBITMQ_CIRCUIT_BREAKER_CONSECUTIVE_FAILURES` | Falhas consecutivas antes de o circuito abrir. | `15` |
| `RABBITMQ_CIRCUIT_BREAKER_FAILURE_RATIO` | Percentual de falha (0–100) que aciona o estado open. | `50` |
| `RABBITMQ_CIRCUIT_BREAKER_MIN_REQUESTS` | Requisições mínimas antes de avaliar a proporção de falhas. | `10` |
| `RABBITMQ_CIRCUIT_BREAKER_INTERVAL` | Janela de tempo (segundos) para contar falhas. Os contadores reiniciam a cada intervalo. | `120` |
| `RABBITMQ_CIRCUIT_BREAKER_TIMEOUT` | Por quanto tempo (segundos) o circuito fica open antes de transicionar para half-open. | `30` |
| `RABBITMQ_CIRCUIT_BREAKER_MAX_REQUESTS` | Requisições permitidas no estado half-open para testar a recuperação. | `3` |
| `RABBITMQ_CIRCUIT_BREAKER_HEALTH_CHECK_INTERVAL` | Com que frequência (segundos) o health checker em segundo plano faz ping no RabbitMQ. | `30` |
| `RABBITMQ_CIRCUIT_BREAKER_HEALTH_CHECK_TIMEOUT` | Timeout (segundos) para cada ping de health check. | `10` |

## Como o modo assíncrono se conecta ao Bulk Recorder

***

O modo assíncrono e o [Bulk Recorder](https://docs.lerian.studio/pt/products/midaz/bulk-recorder.md) trabalham juntos:

1. **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.

2. **O Bulk Recorder** otimiza como o consumidor grava essas mensagens no banco de dados. Ele agrupa várias mensagens em inserções em lote únicas.

| Configuração | Comportamento de processamento |
| :- | :- |
| Async `false` | Gravação direta no banco de dados por transação (síncrono) |
| Async `true`, Bulk Recorder `false` | Baseado em fila, uma mensagem processada por vez |

## Quando usar o modo assíncrono

***

**Use o modo assíncrono quando:**

* Você precisa de tempos de resposta mais baixos da API para a criação de transações.
* Sua carga de trabalho envolve altos volumes de transações (centenas ou mais por segundo).
* Você executa operações em lote, como repasses em massa ou liquidações.
* Você quer desacoplar a camada de API do desempenho do banco de dados.

**Mantenha o modo síncrono quando:**

* Você precisa de persistência de transação direta e vinculada à requisição.
* O volume de transações é baixo a moderado.
* Você trabalha em um ambiente de desenvolvimento ou teste, onde a simplicidade importa mais que o throughput.

> [!TIP]
>
> Você pode alternar entre os modos a qualquer momento. Altere `RABBITMQ_TRANSACTION_ASYNC` e reinicie a aplicação do ledger. Você não precisa de nenhuma migração de dados, porque o formato da transação é o mesmo nos dois caminhos.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.