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

> Usa Bulk Recorder para agrupar los mensajes de RabbitMQ en inserciones masivas de PostgreSQL, lo que reduce los viajes de ida y vuelta a la base de datos y aumenta el rendimiento en cargas de trabajo de alto volumen.

## Por qué esto importa

***

Cada transacción en Midaz crea operaciones de saldo que Midaz debe conservar. En el modo síncrono predeterminado, Midaz las escribe directamente en la base de datos dentro del ciclo de la solicitud. Esto funciona bien para volúmenes moderados. A gran escala (miles de transacciones por segundo), se convierte en el cuello de botella.

Bulk Recorder acumula los mensajes y los escribe en lotes. Hace menos viajes de ida y vuelta a PostgreSQL, reduce la contención de bloqueos y aumenta el rendimiento. Las cargas de trabajo de alto volumen son las que más se benefician: pagos masivos, liquidaciones por lotes y procesamiento de pagos en tiempo real.

Para conocer estrategias más amplias para escalar Midaz, consulta [Estrategias de escalabilidad](/es/products/midaz/scalability-strategies).

## Cómo funciona

***

Bulk Recorder se ubica entre el consumidor de RabbitMQ y la capa de base de datos. No inserta cada mensaje de inmediato. En cambio, recopila los mensajes en un búfer y los vacía bajo dos condiciones:

1. **Se alcanza el tamaño del lote**: el búfer se llena hasta el tamaño configurado.
2. **Se agota el tiempo de espera**: el tiempo de espera de vaciado configurado expira, incluso si el búfer no está lleno.

La condición que ocurra primero activa el vaciado. Esto genera lotes grandes bajo carga y baja latencia durante los períodos tranquilos.

<Frame caption="Figura 1. Flujo de extremo a extremo de Bulk Recorder entre RabbitMQ y PostgreSQL.">
  <img src="https://mintcdn.com/lerian-49cb71fc/RAVxFNT8MNA4GWjO/images/es/d2/bulk-recorder-flow.svg?fit=max&auto=format&n=RAVxFNT8MNA4GWjO&q=85&s=d53a3ce8a380589ef8c9ff3d35054900" alt="Diagrama de secuencia que muestra a RabbitMQ entregando mensajes al BulkCollector, que los almacena en búfer hasta que se alcanza el tamaño del lote o el tiempo de espera, y luego envía un INSERT masivo fragmentado a PostgreSQL y confirma cada mensaje de vuelta a RabbitMQ." className="mx-auto" style={{ width:"80%" }} width="716" height="994" data-path="images/es/d2/bulk-recorder-flow.svg" />
</Frame>

Este es el flujo completo, paso a paso:

1. **RabbitMQ entrega los mensajes** al BulkCollector de a uno a la vez: mensaje 1, mensaje 2, hasta el mensaje N.

2. **El BulkCollector los mantiene en memoria** en lugar de hacer una escritura por mensaje. Recopila hasta que el lote se llena o el tiempo de espera de vaciado expira.

3. **El BulkCollector envía un INSERT masivo fragmentado a PostgreSQL.** Midaz divide los lotes grandes en fragmentos que respetan los límites de parámetros de PostgreSQL. Cada fragmento usa `ON CONFLICT (id) DO NOTHING`, de modo que los reintentos y las entregas duplicadas permanecen seguros.

4. **PostgreSQL confirma la escritura** y almacena los datos.

5. **El BulkCollector confirma cada mensaje** de vuelta a RabbitMQ después de la escritura. Los confirma de a uno a la vez, no en una única confirmación masiva. Esto evita que un canal compartido confirme mensajes que otros workers todavía procesan.

## Habilitar Bulk Recorder

***

El modo bulk requiere el modo asíncrono. El ajuste explícito de Bulk Recorder es opcional porque está habilitado de forma predeterminada:

<CodeGroup>
  ```bash Environment variables theme={null}
  RABBITMQ_TRANSACTION_ASYNC=true
  BULK_RECORDER_ENABLED=true
  ```
</CodeGroup>

El modo asíncrono es obligatorio. Con `RABBITMQ_TRANSACTION_ASYNC=true`, Bulk Recorder está habilitado de forma predeterminada. Establece `BULK_RECORDER_ENABLED=false` para procesar los mensajes en cola de forma individual. Sin el modo asíncrono, Midaz conserva las transacciones directamente en lugar de consumir mensajes en cola.

<Tip>
  `BULK_RECORDER_ENABLED` usa `true` de forma predeterminada cuando no estableces la variable de entorno. Si ya ejecutas con `RABBITMQ_TRANSACTION_ASYNC=true`, el modo bulk probablemente está activo. Para confirmarlo, revisa los registros de tu aplicación en busca de `Bulk mode is ACTIVE` en el arranque.
</Tip>

## Configuración

***

| Variable                         | Descripción                                                                   | Predeterminado   |
| :------------------------------- | :---------------------------------------------------------------------------- | :--------------- |
| `BULK_RECORDER_ENABLED`          | Habilita o deshabilita el modo bulk.                                          | `true`           |
| `BULK_RECORDER_SIZE`             | Número de mensajes que se acumulan antes de vaciar. `0` = cálculo automático. | `0` (automático) |
| `BULK_RECORDER_FLUSH_TIMEOUT_MS` | Tiempo máximo (ms) de espera antes de vaciar un lote incompleto.              | `100`            |

### Tamaño de lote calculado automáticamente

Cuando `BULK_RECORDER_SIZE` está en `0` (el valor predeterminado), Midaz deriva el tamaño del lote:

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

Esto alinea la capacidad del colector con el flujo real de mensajes de RabbitMQ. Evita vaciados parciales y presión de memoria.

<Warning>
  Si estableces `BULK_RECORDER_SIZE` manualmente, mantenlo alineado con tus ajustes de prefetch. Un tamaño mucho mayor que `workers × prefetch` rara vez llena el colector. En ese caso, el colector vacía casi siempre por el tiempo de espera.
</Warning>

## Ajustar para tu carga de trabajo

***

Las dos palancas principales son el **tamaño del lote** y el **tiempo de espera de vaciado**. El equilibrio adecuado depende de tu prioridad: latencia o rendimiento.

### Baja latencia (procesamiento en tiempo real)

Mantén los lotes pequeños y los tiempos de espera cortos. Midaz conserva los mensajes rápidamente, incluso cuando los lotes no están llenos.

<CodeGroup>
  ```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
  ```
</CodeGroup>

### Alto rendimiento (operaciones por lotes)

Los lotes más grandes y los tiempos de espera más largos maximizan la eficiencia de la base de datos. Usa esto para pagos masivos, liquidaciones de fin de día o cargas de trabajo de migración.

<CodeGroup>
  ```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
  ```
</CodeGroup>

<Tip>
  Empieza con los valores predeterminados y ajusta según lo que observes. Para confirmar tus ajustes, busca el registro `Bulk mode configured for consumer` en el arranque.
</Tip>

## Garantías de seguridad

***

Estos mecanismos mantienen seguro a Bulk Recorder:

### Idempotencia

Cada inserción masiva usa `ON CONFLICT (id) DO NOTHING`. Si un mensaje llega dos veces (por un reintento, una reentrega o una falla de red), PostgreSQL descarta el duplicado. No obtienes corrupción de datos ni violaciones de restricciones.

### Prevención de interbloqueos

Antes de cada inserción masiva, Midaz ordena los ID de los registros. Luego, todos los escritores concurrentes adquieren los bloqueos en el mismo orden. Esto elimina la fuente más común de interbloqueos de PostgreSQL bajo alta concurrencia.

### Fragmentación interna

Midaz divide los lotes grandes en fragmentos que caben dentro del límite de 65,535 parámetros por consulta de PostgreSQL:

| Tipo de registro | Columnas por fila | Filas por fragmento | Parámetros por fragmento |
| :--------------- | :---------------- | :------------------ | :----------------------- |
| Transacción      | 18                | 1,000               | 18,000                   |
| Operación        | 31                | 1,000               | 31,000                   |

Midaz gestiona esta fragmentación por ti. Cada `INSERT` lleva como máximo 1,000 filas. `BULK_RECORDER_MAX_ROWS_PER_INSERT` actualmente no se aplica al tamaño del fragmento de PostgreSQL.

## Cuándo usarlo

***

**Usa Bulk Recorder cuando:**

* Procesas grandes volúmenes de transacciones (cientos o miles por segundo).
* Tu carga de trabajo incluye operaciones por lotes como pagos masivos, liquidaciones o migraciones de datos.
* Ya usas el procesamiento asíncrono de transacciones (`RABBITMQ_TRANSACTION_ASYNC=true`).
* Quieres reducir la carga de la base de datos y la presión de conexiones.

**Mantenlo deshabilitado cuando:**

* Tu volumen es lo bastante bajo como para que las inserciones individuales no sean un cuello de botella.
* Necesitas un orden estricto por mensaje que el procesamiento por lotes rompería.
* Depuras el procesamiento de transacciones y quieres un flujo más simple, mensaje por mensaje.
