River: Una cola de trabajos rápida y robusta para Go y Postgres
Una nueva biblioteca de Go llamada River propone usar PostgreSQL como una cola de trabajos transaccional, vinculando la creación de trabajos a las mismas transacciones de base de datos que modifican los datos de la aplicación. Quienes la apoyan argumentan que este enfoque de “una sola dependencia” simplifica la arquitectura, mejora la corrección mediante el encolado atómico y escala lo suficiente para la mayoría de las cargas, citando sistemas similares como Oban como prueba. Quienes la critican responden que las bases de datos relacionales son malas colas a gran escala y prefieren servicios dedicados o sistemas de tareas basados en HTTP, planteando preocupaciones sobre rendimiento, trabajos de larga duración y los compromisos frente a herramientas como Redis, Kafka, Temporal o colas en la nube.
Diseño: Cola de trabajos transaccional respaldada por Postgres
- Idea central: los trabajos se encolan dentro de la misma transacción de la base de datos que los datos de negocio (“transactional outbox” en estilo).
- Esto garantiza que la creación del trabajo sea atómica con los cambios del dominio: o se confirman ambos, o ninguno.
- Los trabajos son procesados por procesos separados; la transacción solo sirve para encolarlos, no para ejecutarlos.
- Existe soporte para trabajos programados (con retraso) mediante una opción
ScheduledAt, aunque la documentación aún se está desarrollando.
RDBMS como cola: pros y contras
- A favor:
- Fuertes garantías de corrección, un modelo mental simple y menos piezas móviles si Postgres ya está en uso.
- Rendimiento suficiente para la mayoría de los sistemas; ejemplos de otros ecosistemas muestran decenas de miles de trabajos/segundo.
- Operaciones más sencillas que añadir Redis/RabbitMQ/Kafka para muchas aplicaciones pequeñas o medianas.
- Escépticos:
- “Las bases de datos son malas colas” sigue siendo una creencia común, citando escalabilidad, crecimiento excesivo y preocupaciones sobre trabajos de larga duración.
- Algunos sostienen que “nunca” usarían un RDBMS como cola de trabajos basándose en experiencia previa.
Detalles de implementación y patrones
- Patrón típico:
SELECT … FOR UPDATE SKIP LOCKED(o variantes) para asignar trabajos de forma segura entre trabajadores. - Se sugieren cosas como:
- Usar
FOR NO KEY UPDATEpara evitar bloquear inserciones con claves foráneas. - Particionar la tabla de trabajos, secuenciación por inquilino y procesamiento masivo mediante leases para mejorar el rendimiento.
- Usar
- Se puede usar
NOTIFYde Postgres para despertar a los trabajadores, pero hay preocupación por la sobrecarga y la incompatibilidad con poolers como PgBouncer. - Algunas funciones están en desarrollo o han sido solicitadas: panel UI, notificaciones de finalización de trabajos, soporte más rico para flujos de trabajo.
Comparaciones con otros sistemas
- Se citan colas de trabajos en Postgres relacionadas en otros lenguajes (por ejemplo, bibliotecas conocidas de Elixir y JS) como antecedentes y evidencia de que el modelo funciona.
- Se discuten alternativas:
- Colas basadas en HTTP (GCP Tasks, enfoques tipo SQS) elogiadas por su simplicidad pero criticadas por problemas de corrección transaccional y límites de tiempo de espera.
- Enfoques basados en Kafka o NATS, motores de workflows parecidos a Temporal y colas puramente SQL (por ejemplo, PGMQ) mencionados como distintos puntos de equilibrio.
Dirección del proyecto, licencia y atribución
- Algunos se preguntan por objetivos comerciales frente a puramente open source y si colas similares en Go deberían “unir fuerzas”.
- Se cuestiona la licencia LGPLv3 para una biblioteca de Go debido al enlazado estático; los mantenedores reconocen que necesitan aclararlo o ajustarlo.
- Hay debate sobre cuánto del diseño se inspiró en sistemas de trabajos basados en Postgres existentes y llamados a una atribución más clara.