> ## 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.

# Bulk Recorder

> Use o Bulk Recorder para agrupar mensagens do RabbitMQ em inserções em massa no PostgreSQL, reduzindo idas e vindas ao banco de dados e aumentando o throughput em cargas de trabalho de alto volume.

## Gravações em lote para cargas de trabalho de alto volume

***

Toda transação no Midaz cria operações de saldo que o Midaz deve persistir. No modo síncrono padrão, o Midaz as grava diretamente no banco de dados durante o ciclo da requisição. Isso funciona bem para volumes moderados. Em escala (milhares de transações por segundo), isso se torna o gargalo.

O Bulk Recorder acumula mensagens e as grava em lotes. Ele reduz as idas e vindas ao PostgreSQL, diminui a disputa por locks e aumenta o throughput. As cargas de trabalho de alto volume ganham mais: pagamentos em massa, liquidações em lote e processamento de pagamentos em tempo real.

Para estratégias mais amplas de escalar o Midaz, veja [Estratégias de escalabilidade](https://docs.lerian.studio/pt/products/midaz/scalability-strategies.md).

## Como funciona

***

O Bulk Recorder fica entre o consumidor do RabbitMQ e a camada de banco de dados. Em vez de inserir cada mensagem de uma vez, ele coleta mensagens em um buffer e as descarrega sob duas condições:

1. **Tamanho de lote atingido**: o buffer atinge o tamanho configurado.
2. **Timeout esgotado**: o timeout de descarga configurado expira, mesmo que o buffer não esteja cheio.

A condição que ocorrer primeiro dispara a descarga. Isso gera lotes grandes sob carga e baixa latência em períodos de baixa atividade.

![Diagrama de sequência mostrando o RabbitMQ entregando mensagens ao BulkCollector, que as armazena em buffer até que o tamanho do lote ou o timeout seja atingido, então envia um INSERT em massa fragmentado ao PostgreSQL e confirma cada mensagem de volta ao RabbitMQ.](https://mintcdn.com/lerian-49cb71fc/vdBt8wfgjsNRO1rf/images/pt/d2/bulk-recorder-flow.svg?fit=max\&auto=format\&n=vdBt8wfgjsNRO1rf\&q=85\&s=46b40a3f202397caee93c7cdae37312b)

Figura 1. Fluxo ponta a ponta do Bulk Recorder entre o RabbitMQ e o PostgreSQL.

Aqui está o fluxo completo, passo a passo:

1. **O RabbitMQ entrega mensagens** ao BulkCollector uma de cada vez: Mensagem 1, Mensagem 2, até a Mensagem N.

2. **O BulkCollector as mantém em memória** em vez de uma gravação por mensagem. Ele coleta até o lote se encher ou o timeout de descarga expirar.

3. **O BulkCollector envia um INSERT em massa fragmentado ao PostgreSQL.** O Midaz divide lotes grandes em fragmentos que respeitam os limites de parâmetro do PostgreSQL. Cada fragmento usa `ON CONFLICT (id) DO NOTHING`, então novas tentativas e entregas duplicadas permanecem seguras.

4. **O PostgreSQL confirma a gravação** e armazena os dados.

5. **O BulkCollector confirma cada mensagem** de volta ao RabbitMQ após a gravação. Ele as confirma uma de cada vez, não em uma única confirmação em massa. Isso evita que um canal compartilhado confirme mensagens que outros workers ainda estão processando.

## Habilitando o Bulk Recorder

***

O modo em massa funciona apenas em um deploy single-tenant e exige o modo assíncrono. A configuração explícita do Bulk Recorder é opcional porque o padrão já é habilitado:

```bash Environment variables theme={null}
RABBITMQ_TRANSACTION_ASYNC=true
BULK_RECORDER_ENABLED=true
```

## Configuração

***

| Variável | Descrição | Padrão |
| :- | :- | :- |
| `BULK_RECORDER_ENABLED` | Habilita ou desabilita o modo em massa. | `true` |
| `BULK_RECORDER_SIZE` | Número de mensagens a acumular antes de descarregar. `0` = calculado automaticamente. | `0` (automático) |
| `BULK_RECORDER_FLUSH_TIMEOUT_MS` | Tempo máximo (ms) de espera antes de descarregar um lote incompleto. | `100` |
| `BULK_RECORDER_MAX_ROWS_PER_INSERT` | Máximo de linhas de operação por `INSERT`. Valores acima de 1.000 não têm efeito. | `1000` |

### Tamanho de lote calculado automaticamente

Quando `BULK_RECORDER_SIZE` é definido como `0` (o padrão), o Midaz calcula o tamanho do lote:

```
batch size = RABBITMQ_NUMBERS_OF_WORKERS × RABBITMQ_NUMBERS_OF_PREFETCH
```

> [!WARNING]
>
> Se você definir `BULK_RECORDER_SIZE` manualmente, mantenha-o alinhado com suas configurações de prefetch. Um tamanho muito maior que `workers × prefetch` raramente enche o coletor. O coletor então descarrega principalmente pelo timeout.

## Ajustando para sua carga de trabalho

***

Os dois principais parâmetros são **tamanho do lote** e **timeout de descarga**. O equilíbrio certo depende da sua prioridade: latência ou throughput.

### Baixa latência (processamento em tempo real)

Mantenha os lotes pequenos e os timeouts curtos. O Midaz persiste as mensagens rapidamente, mesmo quando os lotes não estão cheios.

```bash Low-latency configuration theme={null}
RABBITMQ_NUMBERS_OF_WORKERS=5
RABBITMQ_NUMBERS_OF_PREFETCH=10
BULK_RECORDER_SIZE=0          # auto: 5 × 10 = 50
BULK_RECORDER_FLUSH_TIMEOUT_MS=50
```

### Alto throughput (operações em lote)

Lotes maiores e timeouts mais longos maximizam a eficiência do banco de dados. Use isso para pagamentos em massa, liquidações de fim de dia ou cargas de trabalho de migração.

```bash High-throughput configuration theme={null}
RABBITMQ_NUMBERS_OF_WORKERS=10
RABBITMQ_NUMBERS_OF_PREFETCH=20
BULK_RECORDER_SIZE=0          # auto: 10 × 20 = 200
BULK_RECORDER_FLUSH_TIMEOUT_MS=300
```

> [!TIP]
>
> Comece com os padrões e ajuste a partir do que você observar. Para confirmar suas configurações, procure o log `Bulk mode configured for consumer` na inicialização.

## Garantias de segurança

***

Estes mecanismos mantêm o Bulk Recorder seguro:

### Idempotência

Toda inserção em massa usa `ON CONFLICT (id) DO NOTHING`. Se uma mensagem chegar duas vezes (por uma nova tentativa, uma reentrega ou uma falha de rede), o PostgreSQL descarta a duplicata.

### Prevenção de deadlock

Antes de cada inserção em massa, o Midaz ordena os IDs dos registros. Todos os gravadores concorrentes então adquirem locks na mesma ordem. Isso remove a fonte mais comum de deadlocks do PostgreSQL sob alta concorrência.

### Fragmentação interna

O Midaz divide lotes grandes em fragmentos que cabem dentro do limite de 65.535 parâmetros por consulta do PostgreSQL. Cada `INSERT` carrega no máximo 1.000 linhas.

## Quando usar

***

**Use o Bulk Recorder quando:**

* Você processa altos volumes de transações (centenas ou milhares por segundo).
* Sua carga de trabalho inclui operações em lote como pagamentos em massa, liquidações ou migrações de dados.
* Você já usa processamento assíncrono de transações (`RABBITMQ_TRANSACTION_ASYNC=true`).
* Você quer reduzir a carga do banco de dados e a pressão de conexões.

**Mantenha-o desabilitado quando:**

* Seu volume é baixo o suficiente para que inserções individuais não sejam um gargalo.
* Você está depurando o processamento de transações e quer um fluxo mais simples, mensagem por mensagem.


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