3 puntos por GN⁺ 2026-01-30 | 1 comentarios | Compartir por WhatsApp
  • Oban.py es una versión portada a Python basada en PostgreSQL del framework de procesamiento de jobs Oban de Elixir, y permite insertar y procesar jobs usando solo la base de datos
  • Los jobs se crean y se revierten dentro de transacciones de base de datos, y admite varias funciones como gestión de colas, almacenamiento de resultados y programación cron
  • La versión de código abierto tiene limitaciones como ejecución asyncio de un solo hilo y inserción y confirmación individuales, pero la versión Pro ofrece procesamiento en paralelo, workflows y concurrencia inteligente
  • Su funcionamiento interno se compone de cinco etapas: Insert → Notify → Fetch → Execute → Ack, y usa FOR UPDATE SKIP LOCKED de PostgreSQL para evitar conflictos de concurrencia
  • La elección de líder, la recuperación de jobs huérfanos y los reintentos con backoff también se realizan sobre la base de datos, lo que permite procesamiento distribuido confiable sin brokers externos

Resumen de Oban.py

  • Oban.py es un framework de procesamiento de jobs basado en base de datos que porta Oban de Elixir a Python
    • Inserta y procesa jobs dentro de transacciones de base de datos, y si falla, toda la transacción se revierte
    • Incluye varias funciones de control como límites de cola, almacenamiento de jobs completados, retención de resultados y programación cron
  • Ofrece dos versiones
    • Código abierto (OSS): ejecución asyncio de un solo hilo, inserción y confirmación individuales, recuperación simple
    • Versión Pro: procesamiento en paralelo basado en pool de procesos, con soporte para workflows, relays, jobs únicos y concurrencia inteligente
  • La versión OSS es adecuada para proyectos personales o evaluación, mientras que para entornos a gran escala se recomienda la versión Pro

Ruta de procesamiento de jobs

  • Tras insertar un job, se guarda en la tabla oban_jobs con state='available', y se envía una notificación a cada nodo mediante NOTIFY de PostgreSQL
  • El Stager de cada nodo detecta esa cola y despierta al Producer, y el Producer toma el job para ejecutarlo
  • Al seleccionar jobs se usa FOR UPDATE SKIP LOCKED de SQL, lo que permite procesamiento paralelo sin ejecución duplicada
    • Las filas ya bloqueadas se omiten para que otros producers puedan tomar de inmediato otros jobs
  • Los jobs se despachan como async task y, al completarse, se procesa el acknowledgement mediante callback
  • La versión Pro usa un dispatcher con pool de procesos en lugar de asyncio, lo que permite ejecución paralela en múltiples núcleos

Procesos en segundo plano

  • Elección de líder (Leader Election)
    • Determina al líder con INSERT ... ON CONFLICT de PostgreSQL y un lease basado en TTL
    • Sin un protocolo de consenso aparte, un único líder se encarga de la limpieza y recuperación de jobs
  • Lifeline (recuperación de jobs huérfanos)
    • Si un job en ejecución dura más de cierto tiempo (rescue_after, 5 minutos por defecto), se restaura al estado available
    • La versión Pro verifica si el producer sigue vivo, pero OSS decide solo con base en el tiempo
  • Pruner (limpieza de jobs)
    • Elimina jobs completados, cancelados o descartados cuya antigüedad supere max_age (1 día por defecto)
    • Limita el alcance del borrado con LIMIT para evitar sobrecargar la base de datos

Reintentos y backoff

  • Si un job lanza una excepción, el Executor decide si debe reintentarse
    • Si está por debajo del máximo de intentos (max_attempts), se reintenta; si lo supera, se descarta
  • El backoff por defecto es un incremento exponencial con jitter
    • Esto evita reintentos simultáneos ante fallas masivas y reduce el aumento brusco de carga (Thundering Herd)
    • Ejemplo: espera de unos 17 segundos en el intento 1, unos 47 segundos en el intento 5 y unos 17 minutos en el intento 10
  • La clase worker puede implementar lógica de backoff personalizada con el método backoff()

Características principales y evaluación

  • PostgreSQL cumple un rol central
    • Con FOR UPDATE SKIP LOCKED, LISTEN/NOTIFY y ON CONFLICT resuelve control de concurrencia, señalización y elección de líder
    • Construye una capa de coordinación con una sola base de datos, sin Redis ni brokers externos
  • Sin paralelismo, pero con soporte de concurrencia
    • Al estar basado en asyncio, es adecuado para tareas I/O-bound; para trabajos CPU-bound se recomienda la versión Pro
  • Claridad en la estructura del código
    • Con nombres consistentes y responsabilidades separadas, tiene una base de código fácil de leer
  • Separación clara entre OSS y Pro
    • OSS está orientado a experimentación y pequeña escala; Pro, a entornos grandes y de alto rendimiento
  • Conclusión: es un port limpio y bien estructurado a Python que implementa una cola de jobs completa usando solo PostgreSQL, ideal para usuarios de Elixir o desarrolladores que buscan un sistema de jobs sin infraestructura externa

1 comentarios

 
GN⁺ 2026-01-30
Comentarios de Hacker News
  • Yo soy quien creó Sidekiq, y quiero felicitar a Shannon y Parker por este lanzamiento.
    Antes tuve la misma duda: enfocarme en Ruby o expandir Sidekiq a otros lenguajes. Me di cuenta de que no podía ser experto en todos, así que en su lugar creé Faktory. La idea es que un servidor central gestione el ciclo de vida de la cola, mientras que los clientes de cada lenguaje se mantienen simples. Por ejemplo, existe un cliente como faktory-rs. La desventaja es que, al no enfocarse en una comunidad de lenguaje específica, es difícil ofrecer ejemplos adaptados a ese lenguaje.
    Puede que enfocarse en una sola comunidad dé mejores resultados. El tiempo lo dirá

    • ¡Gracias, Mike! De verdad eres una fuente de inspiración. Parker y yo tenemos fortalezas distintas, y creemos en la sinergia que surge de la interoperabilidad entre Python y Elixir
    • Faktory fue una gran inspiración para mi sistema de colas de trabajos independiente del lenguaje, Ocypod. Gracias por liberarlo como open source
    • En realidad, ¿no sería más preciso decir que ambos están basados en Resque?
    • Quizá no era tu intención, pero tu comentario parece más una promoción de tu proyecto. Ese tipo de cosas aquí no suelen verse bien
    • La expresión “based on” me parece un poco exagerada. Sidekiq es mucho más simple comparado con los flujos de trabajo, cron, particionamiento, trabajos dependientes, manejo de fallos y demás que soporta Oban
  • Lo esencial de Oban es que puedes insertar y procesar trabajos usando solo la base de datos. Puedes meter un trabajo de envío de email dentro de una transacción de creación de usuario, y si falla, todo se revierte.
    Mucha gente dice que no deberías usar una BD relacional como cola de trabajos, pero pasan por alto la importancia de las transacciones. El artículo de Brandur Leach, Job Drain, también explica muy bien esta idea

    • Me identifico muchísimo con eso. Durante años vi cómo se perdían eventos por el Dual Write Problem. Al final volvimos a un enfoque basado en SQL y el problema se resolvió en un solo día.
      Pero ahora ya nadie recuerda esa incomodidad. El patrón transactional outbox es indispensable, y yo prefiero un enfoque que tenga las mismas garantías ACID que mis datos.
      Aunque no conozcas el internals de la BD, si inviertes una semana en aprender niveles de aislamiento y orden de commit, te ahorras un año depurando sistemas distribuidos
    • A eso justamente se le llama patrón transactional outbox
    • A mí también me parece una función realmente genial. En mi caso uso pg_timetable
    • Nosotros estamos creando un constructor de apps con IA, y usamos Elixir, Phoenix y, por supuesto, OBAN.
      En una época con tantos procesos largos de IA, este tipo de durabilidad es indispensable. En otros ecosistemas de lenguaje pagas por tener esto, pero en Oban viene incluido de base
    • Nunca había pensado en las transacciones de esa manera; realmente es impresionante
  • El equipo de Oban es conocido en el ecosistema Elixir por su ingeniería sofisticada. Pero me desconcierta que hayan dejado el pool de procesos bloqueado en la versión Pro.
    Por ejemplo, el plan de $135/mes incluye ejecución multiproceso, flujos de trabajo, límites globales, trabajos únicos, operaciones en lote, fuentes cifradas, soporte dedicado, etc.
    Mi proyecto Chancy es completamente gratis, y permite mezclar libremente asyncio, procesos, hilos y subintérpretes.
    Creo que sería mejor mover estas funciones a OSS y dejar lo de pago más centrado en soporte enterprise. En el ecosistema Python hay muchos más competidores

    • Dependiendo del interés y del uso, puede que algunas funciones pasen a OSS. Ya lo hicimos antes en Elixir.
      El modelo de vender solo soporte no nos funcionó muy bien, aunque en Python podría ser distinto.
      En el ecosistema Python de verdad hay de todo
    • Como referencia, Django 6.0 agregó la Django Tasks API, que permite cambiar el backend, pero todavía no hay un backend realmente listo para producción.
      Si agregas soporte de Django Tasks a Chancy o creas un paquete django-chancy, creo que tendría adopción rápida
    • Gracias por compartir Chancy. Se ve interesante. Más allá de cambios en la API, ¿dirías que ya puede usarse de forma estable en producción?
  • El Oban OSS solo soporta ejecución asyncio de un solo hilo, así que los trabajos CPU-bound bloquean el event loop.
    Por eso sentí que no valía la pena probarlo. La interfaz de Celery no me encanta, pero me resulta familiar y puede escalar vertical y horizontalmente sin límite.
    Aun así, al enterarme de que sí se pueden levantar varios nodos worker, cambié un poco de opinión

  • La separación entre funciones OSS y Pro está bien, pero me decepciona que “la versión Pro rastrea la vida del producer con heartbeats más inteligentes”.
    Que las funciones relacionadas con la confiabilidad sean de pago hace que sea más difícil adoptar el proyecto en OSS

    • Siento lo mismo. Oban es genial, pero da pena que la versión de pago sea “la misma funcionalidad, pero mejor”.
      La versión base debería ser la mejor posible, y lo adicional debería ser lo de pago. La línea divisoria parece estar en un lugar un poco extraño
    • Las colas basadas en Redis o RabbitMQ también pueden perder trabajos tras una terminación inesperada.
      La frase citada es un poco inexacta: el rastreo de vida del producer es igual; la diferencia está solo en cómo se recuperan los trabajos huérfanos
  • Ojalá los flujos de trabajo de BI/ML/DS en Python se mudaran a Elixir.
    Creo que Elixir, con su naturaleza funcional, tolerante a fallos y concurrente, es una base mucho más natural para ese tipo de tareas

  • En nuestra empresa también usamos Celery, y la verdad no nos gusta mucho. Temporal es demasiado pesado, mientras que Oban se siente ligero y atractivo.
    Me interesa una comparación de alguien que haya usado ambos

    • Las filosofías de ambas herramientas son completamente distintas.
      Temporal encaja mejor en organizaciones que pueden asumir la complejidad a cambio de garantías de workflow, por ejemplo un banco.
      Oban es una cola basada en BD, y la confiabilidad tienes que reforzarla tú mismo.
      A mí me parece bien que ambos estén presentes dentro de un sistema
    • Nosotros migramos de Celery a Prefect y estamos satisfechos. Es perfecto para procesar tareas por miles.
      Usamos una combinación de ProcessWorker simple y workers en ECS
    • Hace poco volví al desarrollo web con Python después de mucho tiempo, y me sorprendió ver tantas quejas sobre Celery.
      Me pregunto si últimamente Celery se ha vuelto menos estable o más difícil de manejar
  • Proyecto interesante. Pero sí destaca que algunas funciones clave estén solo en Pro.
    Como proyectos previos que implementan workflows durables basados en Postgres en OSS, están DBOS y Absurd.
    Da gusto ver que el enfoque centrado en la base de datos vaya ganando terreno

    • En Elixir también hubo proyectos OSS parecidos, y la implementación de workflows durables de Oban se adelantó varios años a DBOS.
      Un modelo totalmente open source y sostenido solo por venta de soporte es un modelo soñado. Ojalá algún día sea posible
  • Me pregunto si Postgres da rendimiento suficiente para procesar cientos de millones de trabajos. En el pasado vi una gran mejora de rendimiento al migrar a Redis + Sidekiq

    • Me da curiosidad en qué período de tiempo. Yo estoy procesando 20 millones de trabajos al día con Rails/Solid Queue + Postgres en una VM de $45, y todavía tengo bastante margen
  • Dicen que en la versión OSS, si hay trabajos largos, pueden recuperarse incorrectamente aunque el producer siga vivo.
    Entonces, ¿solo sirve para trabajos cortos?

    • No hay límite en la duración de los trabajos. La diferencia está solo en la velocidad de recuperación tras un fallo.
      El momento de recuperación solo cambia cuando no se pudo esperar una terminación normal