Por qué esto es importante
Cada transacción en Midaz genera operaciones de saldo que necesitan ser persistidas. En el modo predeterminado (sincrónico), cada mensaje desencadena una inserción individual en la base de datos. Eso está bien para volúmenes moderados, pero a escala — miles de transacciones por segundo — se convierte en el cuello de botella. El Bulk Recorder cambia esto acumulando mensajes y escribiéndolos en lotes. Menos viajes de ida y vuelta a PostgreSQL, menos contención de bloqueos y un rendimiento significativamente mayor. Para operaciones de alto volumen como pagos masivos, liquidaciones por lotes o procesamiento de pagos en tiempo real, esta es la diferencia entre un sistema que mantiene el ritmo y uno que no. Para estrategias más amplias sobre cómo escalar Midaz, consulta Estrategias de escalabilidad.
Cómo funciona
El Bulk Recorder se sitúa entre el consumidor de RabbitMQ y la capa de base de datos. En lugar de insertar cada mensaje inmediatamente, los recopila en un búfer y los descarga bajo dos condiciones:
- Tamaño de lote alcanzado — el búfer se llena hasta el tamaño configurado.
- Tiempo de espera agotado — expira el tiempo de espera de descarga configurado, incluso si el búfer no está lleno.

- RabbitMQ entrega los mensajes al BulkCollector uno a la vez — Mensaje 1, Mensaje 2, y así hasta el Mensaje N.
- El BulkCollector los mantiene en memoria en lugar de escribir cada uno inmediatamente. Sigue recopilando hasta que se alcanza el tamaño del lote o expira el tiempo de espera de descarga.
- El BulkCollector envía un INSERT en lote fragmentado a PostgreSQL. Los lotes grandes se dividen automáticamente en fragmentos que respetan los límites de parámetros de PostgreSQL. Cada fragmento utiliza
ON CONFLICT (id) DO NOTHING, por lo que los reintentos y las entregas duplicadas se manejan de forma segura. - PostgreSQL confirma la escritura, asegurando que los datos fueron persistidos.
- El BulkCollector confirma todos los mensajes de vuelta a RabbitMQ en un único ACK, liberándolos de la cola en conjunto.
Habilitar el Bulk Recorder
El modo en lote requiere que dos condiciones estén activas simultáneamente:
Configuración
| Variable | Descripción | Predeterminado |
|---|---|---|
BULK_RECORDER_ENABLED | Habilita o deshabilita el modo en lote. | true |
BULK_RECORDER_SIZE | Número de mensajes a acumular antes de descargar. 0 = calculado automáticamente. | 0 (automático) |
BULK_RECORDER_FLUSH_TIMEOUT_MS | Tiempo máximo (ms) de espera antes de descargar un lote incompleto. | 100 |
BULK_RECORDER_MAX_ROWS_PER_INSERT | Máximo de filas por sentencia INSERT enviada a PostgreSQL. | 1000 |
Tamaño de lote calculado automáticamente
CuandoBULK_RECORDER_SIZE se establece en 0 (el valor predeterminado), el tamaño del lote se deriva automáticamente:
Ajuste para tu carga de trabajo
Las dos palancas principales son el tamaño del lote y el tiempo de espera de descarga. El equilibrio correcto depende de si priorizas la latencia o el rendimiento.
Baja latencia (procesamiento en tiempo real)
Mantén los lotes pequeños y los tiempos de espera cortos. Los mensajes se persisten rápidamente, incluso si los lotes no están llenos.Alto rendimiento (operaciones por lotes)
Lotes más grandes y tiempos de espera más largos maximizan la eficiencia de la base de datos. Ideal para pagos masivos, liquidaciones de fin de día o cargas de trabajo de migración.Garantías de seguridad
El Bulk Recorder está diseñado para ser seguro en todas las condiciones:
Idempotencia
Cada inserción en lote utilizaON CONFLICT (id) DO NOTHING. Si un mensaje se entrega dos veces — debido a un reintento, una re-entrega o un problema de red — el duplicado se descarta silenciosamente. Sin corrupción de datos, sin violaciones de restricciones.
Prevención de deadlocks
Antes de cada inserción en lote, los IDs de los registros se ordenan. Esto garantiza que todos los escritores concurrentes adquieran los bloqueos en el mismo orden, eliminando la fuente más común de deadlocks de PostgreSQL en escenarios de alta concurrencia.Fragmentación interna
Los lotes grandes se dividen automáticamente en fragmentos que se ajustan al límite de 65.535 parámetros por consulta de PostgreSQL:| Tipo de registro | Columnas por fila | Filas por fragmento | Parámetros por fragmento |
|---|---|---|---|
| Transaction | 15 | 1.000 | 15.000 |
| Operation | 30 | 1.000 | 30.000 |
BULK_RECORDER_MAX_ROWS_PER_INSERT si deseas ajustar el tamaño del fragmento — el valor predeterminado de 1.000 filas es óptimo para la mayoría de los deployments.
Cuándo usar
Usa el Bulk Recorder cuando:
- Procesas altos 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 estás utilizando procesamiento asíncrono de transacciones (
RABBITMQ_TRANSACTION_ASYNC=true). - Deseas reducir la carga de la base de datos y la presión de conexión.
- Tu volumen es lo suficientemente bajo como para que las inserciones individuales no sean un cuello de botella.
- Necesitas garantías estrictas de ordenamiento por mensaje que el procesamiento por lotes rompería.
- Estás depurando el procesamiento de transacciones y quieres un flujo más simple, mensaje por mensaje.

