3 pontos por GN⁺ 2026-01-30 | 1 comentários | Compartilhar no WhatsApp
  • Oban.py é uma versão portada para Python, baseada em PostgreSQL, do framework de processamento de jobs Oban, do Elixir, permitindo inserir e processar jobs apenas com o banco de dados
  • Os jobs são criados e revertidos dentro de transações do banco de dados, com suporte a vários recursos como gerenciamento de filas, armazenamento de resultados e agendamento via cron
  • A versão open source tem limitações como execução asyncio em thread única e inserção/confirmação individual, mas a versão Pro oferece processamento paralelo, workflows e concorrência inteligente
  • O funcionamento interno é composto por cinco etapas: Insert → Notify → Fetch → Execute → Ack, usando FOR UPDATE SKIP LOCKED do PostgreSQL para evitar conflitos de concorrência
  • Eleição de líder, recuperação de jobs órfãos e tentativas com backoff também são feitas com base no banco de dados, permitindo processamento distribuído estável sem broker externo

Visão geral do Oban.py

  • Oban.py é um framework de processamento de jobs baseado em banco de dados portado do Oban, do Elixir, para Python
    • Ele insere e processa jobs dentro de transações do banco de dados, e em caso de falha toda a transação é revertida
    • Inclui vários recursos de controle, como limites de fila, armazenamento de jobs concluídos, retenção de resultados e agendamento via cron
  • Há duas versões disponíveis
    • Open source (OSS): execução asyncio em thread única, inserção/confirmação individual, recuperação simples
    • Versão Pro: paralelismo com base em pool de processos, suporte a workflows, relay, jobs únicos e concorrência inteligente
  • A OSS é adequada para projetos pessoais ou avaliação, enquanto a versão Pro é recomendada para ambientes de grande escala

Fluxo de processamento de jobs

  • Após a inserção, o job é salvo na tabela oban_jobs com state='available', e o NOTIFY do PostgreSQL envia notificações para cada nó
  • O Stager de cada nó detecta a fila correspondente e desperta o Producer, que então busca e executa o job
  • Na seleção de jobs, usa-se FOR UPDATE SKIP LOCKED do SQL para permitir processamento paralelo sem execução duplicada
    • Linhas já bloqueadas são ignoradas, permitindo que outro producer pegue imediatamente outros jobs
  • Os jobs são despachados como async task e, ao concluir, passam por acknowledgement via callback
  • A versão Pro usa um dispatcher com pool de processos em vez de asyncio, permitindo execução paralela em múltiplos núcleos

Processos em segundo plano

  • Eleição de líder (Leader Election)
    • O líder é definido com INSERT ... ON CONFLICT do PostgreSQL e leases com TTL
    • Sem protocolo de consenso separado, um único líder fica responsável por limpeza e recuperação de jobs
  • Lifeline (recuperação de jobs órfãos)
    • Se um job em execução durar mais do que um certo tempo (rescue_after, padrão de 5 minutos), ele é restaurado para o estado available
    • A versão Pro verifica se o producer ainda está vivo, mas a OSS julga isso apenas com base no tempo
  • Pruner (limpeza de jobs)
    • Remove jobs concluídos, cancelados ou descartados que já passaram de max_age (padrão de 1 dia)
    • Limita o escopo de exclusão com LIMIT para evitar sobrecarga no banco de dados

Tentativas e backoff

  • Quando um job gera uma exceção, o Executor decide se ele deve ser tentado novamente
    • Se estiver abaixo do número máximo de tentativas (max_attempts), ele é reenfileirado; se ultrapassar, é descartado
  • O backoff padrão é um crescimento exponencial com jitter
    • Isso reduz picos de carga (Thundering Herd) ao evitar novas tentativas simultâneas em falhas em massa
    • Ex.: cerca de 17 segundos na 1ª tentativa, cerca de 47 segundos na 5ª e cerca de 17 minutos na 10ª
  • A classe worker pode implementar lógica personalizada de backoff com o método backoff()

Principais características e avaliação

  • O PostgreSQL desempenha papel central
    • Com FOR UPDATE SKIP LOCKED, LISTEN/NOTIFY e ON CONFLICT, ele cuida de controle de concorrência, sinalização e eleição de líder
    • Sem Redis ou broker externo, a camada de coordenação é formada com um único banco de dados
  • Não é paralelo, mas suporta concorrência
    • Por ser baseado em asyncio, é adequado para tarefas I/O-bound; para tarefas CPU-bound, recomenda-se a versão Pro
  • Clareza na estrutura do código
    • Com nomenclatura consistente e responsabilidades bem separadas, resulta em uma base de código fácil de ler
  • Separação clara entre OSS e Pro
    • A OSS é voltada a experimentação e pequeno porte; a Pro, a ambientes de grande escala e alto desempenho
  • Conclusão: um port limpo e bem estruturado para Python que implementa uma fila de jobs completa apenas com PostgreSQL, adequado para usuários de Elixir ou desenvolvedores que querem um sistema de jobs sem infraestrutura externa

1 comentários

 
GN⁺ 2026-01-30
Comentários no Hacker News
  • Eu sou a pessoa que criou o Sidekiq, e quero parabenizar Shannon e Parker pelo lançamento
    Já passei por esse mesmo dilema antes — focar no Ruby ou expandir o Sidekiq para outras linguagens. Percebi que não dá para ser especialista em todas as linguagens, então em vez disso criei o Faktory. A estrutura é de um servidor central que gerencia o ciclo de vida da fila, enquanto os clientes de cada linguagem permanecem simples. Por exemplo, existe um cliente como o faktory-rs. A desvantagem é não estar focado em uma comunidade de linguagem específica, então fica difícil oferecer exemplos adaptados àquela linguagem.
    Pode ser que uma abordagem focada em uma comunidade gere resultados melhores. O tempo dirá

    • Obrigado, Mike! Você é realmente uma fonte de inspiração. Parker e eu temos pontos fortes diferentes, e acreditamos na sinergia que surge da interoperabilidade entre Python e Elixir
    • O Faktory foi uma grande inspiração para o sistema de fila de jobs independente de linguagem que criei, o Ocypod. Obrigado por disponibilizá-lo como open source
    • Na verdade, não seria mais correto dizer que ambos são baseados em Resque?
    • Talvez não tenha sido sua intenção, mas seu comentário parece uma tentativa de divulgar seu projeto. Esse tipo de coisa não costuma ser muito bem visto aqui
    • A expressão “based on” parece um pouco exagerada. O Sidekiq é bem mais simples em comparação com os workflows, cron, particionamento, jobs dependentes, tratamento de falhas etc. que o Oban oferece
  • O ponto central do Oban é que você consegue inserir e processar jobs usando apenas o banco de dados. Dá para enfileirar um job de envio de e-mail dentro da transação de criação do usuário, e se ela falhar tudo é revertido junto.
    Muita gente diz que não se deve usar banco relacional como fila de jobs, mas ignora a importância das transações. O texto Job Drain, do Brandur Leach, também explica bem esse conceito

    • Concordo profundamente com isso. Passei anos vendo eventos sumirem por causa do Dual Write Problem. No fim, voltamos para uma abordagem baseada em SQL e o problema foi resolvido em um dia.
      Mas agora ninguém mais se lembra daquele incômodo. O “padrão de outbox transacional” é indispensável, e eu prefiro uma abordagem que receba as mesmas garantias ACID que os meus dados.
      Mesmo sem conhecer o internals do banco, investir uma semana para aprender nível de isolamento e ordem de commit pode poupar um ano de depuração de sistemas distribuídos
    • Isso é justamente o que se chama de padrão de outbox transacional
    • Também acho esse recurso muito legal. No meu caso, porém, estou usando pg_timetable
    • Estamos criando um app builder baseado em IA, usando Elixir, Phoenix e, claro, OBAN.
      Em uma época com tantos processos longos de IA, esse tipo de durabilidade é essencial. Em outros ecossistemas isso costuma ser cobrado à parte, mas no Oban já vem incluído
    • Eu nunca tinha pensado em transações dessa forma, fiquei realmente impressionado
  • A equipe do Oban é conhecida por sua engenharia sofisticada no ecossistema Elixir. Mas foi confuso ver o pool de processos trancado na versão Pro.
    Por exemplo, o plano de US$ 135/mês inclui execução multiprocessos, workflows, limites globais, jobs únicos, operações em lote, sources criptografadas, suporte dedicado etc.
    O meu projeto Chancy é totalmente gratuito, e permite combinar livremente asyncio, processos, threads e subinterpreters.
    Acho que seria melhor levar esses recursos para o OSS e deixar o pago mais focado em suporte enterprise. No ecossistema Python há muito mais concorrentes

    • Dependendo do interesse e do uso, alguns recursos podem ir para o OSS. Já fizemos isso no Elixir também.
      O modelo de vender apenas suporte não funcionou muito bem, mas no Python pode ser diferente.
      No ecossistema Python realmente tem de tudo
    • Só para referência, o Django 6.0 adicionou a Django Tasks API, que permite trocar o backend, mas ainda não existe um backend realmente voltado para produção.
      Se o Chancy ganhar suporte a Django Tasks, ou surgir um pacote django-chancy, acho que a adoção seria rápida
    • Obrigado por compartilhar o Chancy. Parece interessante. Tirando mudanças de API, ele já pode ser usado de forma estável em produção agora?
  • O Oban OSS só oferece execução asyncio single-threaded, então jobs CPU-bound bloqueiam o event loop.
    Por isso achei que não valia a pena tentar. A interface do Celery não é grande coisa, mas é familiar, e permite escalar vertical e horizontalmente sem limite.
    Ainda assim, depois que descobri que é possível subir vários nós de worker, mudei um pouco de opinião

  • A divisão entre recursos OSS/Pro é aceitável, mas é uma pena ver algo como “a versão Pro rastreia a vida do producer com heartbeats mais inteligentes”.
    Colocar recursos relacionados à confiabilidade atrás de pagamento dificulta a adoção em projetos OSS

    • Tenho a mesma sensação. O Oban é legal, mas é uma pena quando a versão paga é “uma versão melhor da mesma funcionalidade”.
      A versão básica deveria ser a melhor possível, e os extras deveriam ser pagos. Parece que essa fronteira está em um lugar meio estranho
    • Filas baseadas em Redis ou RabbitMQ também podem perder jobs após encerramentos inesperados.
      A frase citada é um pouco imprecisa — o rastreamento de vida do producer é o mesmo; a diferença está apenas na forma de recuperar jobs órfãos
  • Seria ótimo se workflows de BI/ML/DS em Python migrassem para Elixir.
    Acho que o Elixir, com sua natureza funcional, tolerância a falhas e concorrência, é uma base muito mais natural para esse tipo de trabalho

  • Aqui na empresa também usamos Celery, e não é tão bom assim. Temporal é pesado demais, enquanto o Oban parece leve e interessante.
    Gostaria de ver uma comparação de alguém que já usou os dois

    • As filosofias das duas ferramentas são completamente diferentes.
      O Temporal é adequado para organizações que precisam das garantias de workflow e conseguem arcar com a complexidade, como bancos.
      O Oban é uma fila baseada em banco de dados, cuja confiabilidade precisa ser reforçada por quem usa.
      Eu acho bom ter os dois no sistema ao mesmo tempo
    • Nós migramos do Celery para Prefect e estamos satisfeitos. É perfeito para processar jobs na casa dos milhares.
      Estamos usando uma combinação de ProcessWorker simples com workers em ECS
    • Voltei para desenvolvimento web em Python depois de muito tempo, e fiquei surpreso com a quantidade de reclamações sobre o Celery.
      Fico curioso se o Celery ficou menos estável recentemente, ou só mais difícil de lidar
  • Projeto interessante. Mas chama atenção o fato de alguns recursos centrais estarem disponíveis apenas na versão Pro.
    Como projetos anteriores que implementaram workflows duráveis baseados em Postgres como OSS, há o DBOS e o Absurd.
    É bom ver essa abordagem centrada no banco de dados ganhando espaço

    • No Elixir também houve projetos OSS parecidos, e a implementação de workflows duráveis do Oban veio alguns anos antes da do DBOS.
      Um modelo totalmente open source sustentado apenas pela venda de suporte é um modelo dos sonhos. Espero que um dia seja possível
  • Fico curioso se o Postgres tem desempenho suficiente para processar centenas de milhões de jobs. No passado, vi um grande ganho de performance ao migrar para Redis + Sidekiq

    • Gostaria de saber em qual período. Eu processa 20 milhões de jobs por dia com Rails/Solid Queue + Postgres em uma VM de US$ 45, com bastante folga
  • A versão OSS diz que jobs longos podem ser recuperados incorretamente mesmo quando o producer ainda está vivo.
    Então ela serve apenas para jobs curtos?

    • Não há limite para a duração dos jobs. A diferença está apenas na velocidade de recuperação após falha.
      O timing de recuperação só muda quando não foi possível esperar um encerramento normal