Cuando las escrituras síncronas se convierten en el cuello de botella
Un cliente envía una transacción. Midaz debe hacer dos cosas: validarla y persistir el resultado. En el modo síncrono, ambos pasos se ejecutan en la misma solicitud. Este modelo es simple y predecible, pero tiene un límite. Con un volumen alto, las escrituras a la base de datos se convierten en el cuello de botella. Cada transacción retiene una conexión, espera bloqueos y compite por I/O. El modo asíncrono rompe esa dependencia. Midaz valida la transacción, devuelve la respuesta de inmediato y persiste los datos en segundo plano mediante RabbitMQ. El cliente obtiene respuestas más rápidas. Para una guía más amplia de escalabilidad, consulta Estrategias de escalabilidad.
Cómo funciona
Modo síncrono (predeterminado)
Figura 1. Flujo de transacción síncrono.
-
El cliente envía un
POST /transactiona la API de Midaz. - La API valida la solicitud. Aquí ejecuta la validación de forma de la solicitud, las verificaciones de saldo y la aplicación de límites.
- La API escribe en PostgreSQL. Persiste la transacción y sus operaciones dentro del mismo ciclo de solicitud.
-
La API devuelve
201 Createdal cliente con la transacción creada. La respuesta lleva el estadoCREATED, y Midaz almacena la transacción comoAPPROVED. Un201significa que Midaz aplicó la transacción a los saldos.
- El tiempo de respuesta incluye la latencia de la escritura en la base de datos.
- Cada transacción es una operación de base de datos independiente.
- Más simple de razonar.
Incluso en modo síncrono, Midaz actualiza los saldos de forma atómica en Redis durante la solicitud. Redis es la fuente autoritativa de los saldos. La escritura anterior persiste la transacción y sus operaciones, no las filas de saldo en Postgres. El worker de sincronización de saldos, siempre activo, reconcilia esas filas (consulta Sincronización de saldos).
Modo asíncrono
Midaz valida la transacción de la misma forma. En lugar de una escritura directa a la base de datos, Midaz publica un mensaje en RabbitMQ. Un consumidor en segundo plano recoge el mensaje y maneja la persistencia por separado.Figura 2. Flujo de transacción asíncrono. El cliente recibe una respuesta en cuanto se publica el mensaje, y la persistencia ocurre en segundo plano.
-
El cliente envía un
POST /transactiona la API de Midaz. - La API valida la solicitud. Ejecuta la validación de forma de la solicitud, las verificaciones de saldo y la aplicación de límites exactamente igual que en el modo síncrono.
- La API publica el payload de la transacción en RabbitMQ en lugar de una escritura directa a la base de datos.
-
La API devuelve
201 Createdal cliente en cuanto la cola acepta el mensaje. El cliente no espera la persistencia en la base de datos. La respuesta lleva el estadoCREATED, y Midaz almacena la transacción comoAPPROVED. Un201significa que Midaz aplicó la transacción a los saldos. - RabbitMQ entrega el mensaje a un consumidor en segundo plano, desacoplado de la solicitud de la API.
- El consumidor escribe en PostgreSQL. Persiste la transacción y sus operaciones a partir del mensaje en cola. El worker de sincronización de saldos copia los saldos a PostgreSQL en ambos modos (consulta la sección Sincronización de saldos).
- El tiempo de respuesta excluye la latencia de la escritura en la base de datos.
- Las consultas de lista muestran una transacción nueva después de que el consumidor la escribe.
- Los consumidores en segundo plano escriben en la base de datos a su propio ritmo, con reintentos. Las inserciones por lote requieren que el Bulk Recorder esté habilitado.
Resiliencia integrada
Si la publicación en RabbitMQ falla en el modo asíncrono, Midaz escribe la transacción en la base de datos durante la solicitud. Si esa escritura también falla, la transacción sigue aplicada a los saldos. Midaz conserva el registro de la transacción y reintenta la escritura en segundo plano. El modo síncrono usa la misma recuperación cuando falla su escritura en la base de datos. Esto significa:
- Durante una interrupción de la cola, Midaz escribe directamente en la base de datos.
- Una escritura fallida en la base de datos no rechaza una transacción que Midaz ya aplicó a los saldos.
- Midaz registra la falla de la cola y la escritura diferida, para que tu equipo de operaciones pueda investigarlas.
Habilitar el modo asíncrono
Define una variable de entorno en la aplicación del ledger:
false (el valor predeterminado), todas las transacciones usan procesamiento síncrono y persisten directamente en PostgreSQL. El ledger de todos modos se conecta a RabbitMQ y ejecuta su consumidor en este modo.
Con true, el ledger publica los payloads de transacción en el exchange de RabbitMQ configurado. Un consumidor en segundo plano maneja entonces la persistencia.
Configuración de RabbitMQ
El modo asíncrono usa la siguiente configuración de RabbitMQ (todo en el
.env del ledger):
Sincronización de saldos
Un worker dedicado de sincronización de saldos copia los saldos de Redis a PostgreSQL. Este worker se ejecuta tanto en modo síncrono como en modo asíncrono.
El worker de sincronización de saldos se ejecuta automáticamente en ambos modos. No necesitas configuración adicional más allá de una instancia de Redis disponible.
Circuit breaker de RabbitMQ
Un circuit breaker integrado protege las publicaciones en RabbitMQ de mensajes de auditoría y eventos de sobregiro. Monitorea el estado de la conexión con RabbitMQ y falla rápido cuando el broker cae. Esto evita la acumulación de solicitudes y las fallas en cascada.
Configuración del circuit breaker
Cómo se conecta el modo asíncrono con Bulk Recorder
El modo asíncrono y el Bulk Recorder trabajan juntos:
- El modo asíncrono desacopla la respuesta de la API de la persistencia. Las transacciones van a RabbitMQ en lugar de ir directamente a PostgreSQL.
- Bulk Recorder optimiza cómo el consumidor escribe esos mensajes en la base de datos. Agrupa varios mensajes en inserciones masivas únicas.
Cuándo usar el modo asíncrono
Usa el modo asíncrono cuando:
- Necesitas tiempos de respuesta de API más bajos para la creación de transacciones.
- Tu carga de trabajo implica volúmenes altos de transacciones (cientos o más por segundo).
- Ejecutas operaciones por lote como pagos masivos o liquidaciones.
- Quieres desacoplar tu capa de API del rendimiento de la base de datos.
- Necesitas persistencia de transacciones directa, ligada a la solicitud.
- El volumen de transacciones es bajo o moderado.
- Trabajas en un entorno de desarrollo o pruebas donde la simplicidad importa más que el throughput.

