- Oban.py は、Elixir のジョブ処理フレームワーク Oban を PostgreSQL ベースで Python に移植したバージョンで、データベースだけでジョブを投入して処理できる
- ジョブはデータベーストランザクション内で生成・ロールバックされ、キュー管理・結果保存・cron スケジューリング など多様な機能をサポート
- オープンソース版は 単一スレッドの asyncio 実行 や 個別投入・確認処理 などの制約がある一方、Pro 版は 並列処理・ワークフロー・スマート並行性 を提供
- 内部動作は
Insert → Notify → Fetch → Execute → Ack の5段階で構成され、PostgreSQL の FOR UPDATE SKIP LOCKED を活用して並行性の競合を防止
- リーダー選出、孤立ジョブの復旧、バックオフ再試行などもデータベースベースで実行され、外部ブローカーなしで安定した分散処理 を可能にする
Oban.py 概要
- Oban.py は Elixir の Oban を Python に移植した データベースベースのジョブ処理フレームワーク
- ジョブをデータベーストランザクション内で投入・処理し、失敗時にはトランザクション全体がロールバックされる
- キュー制限、完了ジョブ保存、結果保持、cron スケジューリング など多様な制御機能を含む
- 2つのバージョンを提供
- オープンソース(OSS) : 単一スレッドの asyncio 実行、個別投入・確認、単純な復旧
- Pro 版: プロセスプールベースの並列処理、ワークフロー・リレー・ユニークジョブ・スマート並行性 をサポート
- OSS は個人プロジェクトや評価用途に適しており、大規模環境では Pro 版が推奨される
ジョブ処理の流れ
- ジョブ投入後、
oban_jobs テーブルに state='available' で保存され、PostgreSQL の NOTIFY によって各ノードへ通知が送られる
- 各ノードの Stager が該当キューを検知して Producer を起こし、Producer がジョブを取得して実行する
- ジョブ選択時には SQL の
FOR UPDATE SKIP LOCKED を使い、重複実行なしの並列処理 が可能
- すでにロックされた行はスキップするため、別の Producer が別ジョブを即座に取得できる
- ジョブは async task としてディスパッチされ、完了時にはコールバックで acknowledgement を処理
- Pro 版は asyncio の代わりに プロセスプールディスパッチャ を使い、マルチコア並列実行をサポート
バックグラウンドプロセス
- リーダー選出(Leader Election)
- PostgreSQL の
INSERT ... ON CONFLICT と TTL ベースのリースでリーダーを決定
- 別途コンセンサスプロトコルなしで単一リーダーが ジョブ整理・復旧 を担当
- Lifeline(孤立ジョブ復旧)
- 実行中のジョブが一定時間(
rescue_after、デフォルト5分)を超えて継続すると available 状態に復旧 される
- Pro 版は Producer の生存確認を行うが、OSS は時間ベースでのみ判断する
- Pruner(ジョブ整理)
- 完了・キャンセル・破棄されたジョブのうち、
max_age(デフォルト1日)を超えた項目を削除
LIMIT で削除範囲を制限し、データベース負荷を防ぐ
再試行とバックオフ
- ジョブが例外を発生させると Executor が再試行の可否を判断
- 最大試行回数(
max_attempts)未満なら再試行し、超過すると破棄
- デフォルトのバックオフは ジッター(jitter) を含む 指数的増加
- 大量失敗時の同時再試行を防ぎ、負荷急増(Thundering Herd)を緩和
- 例: 1回目は約17秒、5回目は約47秒、10回目は約17分待機
- ワーカークラスは
backoff() メソッドで ユーザー定義のバックオフロジック を実装できる
主な特徴と評価
- PostgreSQL が中核的な役割 を担う
FOR UPDATE SKIP LOCKED、LISTEN/NOTIFY、ON CONFLICT によって 並行性制御・シグナル伝達・リーダー選出 をすべて処理
- Redis や外部ブローカーなしで 単一データベースによる調整レイヤー を構成
- 並列ではないが並行性をサポート
- asyncio ベースで I/O バウンド作業に適しており、CPU バウンド作業には Pro 版が推奨される
- コード構造の明快さ
- 一貫した命名と責務分離により 読みやすいコードベース を実現
- OSS と Pro の役割分担が明確
- OSS は実験・小規模向け、Pro は大規模・高性能環境向け
- 結論: PostgreSQL だけで完全なジョブキューを実装した クリーンで構造的な Python 移植版 であり、Elixir ユーザーや外部インフラなしのジョブシステムを求める開発者に適している
1件のコメント
Hacker Newsの反応
私は Sidekiq の作者だが、今回 Shannon と Parker がリリースしたものを祝福したい
以前、私も同じことで悩んだ — Ruby に集中するか、それとも Sidekiq を他の言語へ広げるか。すべての言語の専門家にはなれないと気づき、その代わりに Faktory を作った。これは中央サーバーがキューのライフサイクルを管理し、各言語向けクライアントはシンプルなままにしておく構造だ。たとえば faktory-rs のようなクライアントがある。欠点は特定の言語コミュニティに集中していないので、その言語に合った例を提供しづらい点だ。
ひとつのコミュニティに集中するアプローチのほうが、より良い結果を生むかもしれない。時間が教えてくれるだろう
Oban の核心は、データベースだけでジョブの投入と処理ができる点にある。ユーザー作成トランザクションの中でメール送信ジョブも一緒に投入し、失敗したら全体がロールバックされる構造だ。
多くの人はリレーショナル DB をジョブキューとして使うべきではないと言うが、トランザクションの重要性を見落としている。Brandur Leach の記事 Job Drain でもこの考え方がよく説明されている
だが今では誰もその不便さを覚えていない。“トランザクショナル・アウトボックス・パターン” は必須であり、私は自分のデータと同じ ACID 保証 を受けられる方法を好む。
DB の内部実装を知らなくても、分離レベルとコミット順序を学ぶのに 1 週間投資すれば、分散システムのデバッグ 1 年分を節約できる
長い AI プロセスが多い時代において、このような 耐久性 は必須だ。他の言語エコシステムではこうした機能にお金を払うが、Oban では標準で提供されている
Oban チームは Elixir エコシステムで 洗練されたエンジニアリング で知られている。だが、プロ版でプロセスプールをロックしているのは戸惑う。
たとえば月額 135 ドルのプランには、マルチプロセス実行、ワークフロー、グローバル制限、ユニークジョブ、バルク処理、暗号化されたソース、専用サポートなどが含まれる。
私のプロジェクト Chancy は完全に無料で、asyncio、プロセス、スレッド、サブインタープリタを自由に組み合わせられる。
こうした機能を OSS に移して、有料は エンタープライズサポート 中心にしたほうがよいのではと思う。Python エコシステムには競合がはるかに多い
単にサポートだけを売るモデルはうまく合わなかったが、Python では違うかもしれない。
Python エコシステムには本当に 何でもある
Chancy に Django Tasks 対応を追加するか、
django-chancyパッケージを作れば、すぐに採用が進みそうだOSS Oban は 単一スレッドの asyncio 実行 しかサポートしていないので、CPU バウンドなジョブがイベントループをブロックする。
そのため試す価値はないと感じた。Celery のインターフェースは好きではないが慣れているし、垂直・水平の両方でいくらでもスケールできる。
ただ、複数のワーカーノードを立ち上げられると知って少し考えが変わった
OSS/Pro の機能分離自体は構わないが、「Pro 版はより賢いハートビートでプロデューサーの生存を追跡する」というのは残念だ。
信頼性に関わる機能 が有料だと、OSS プロジェクトで採用しにくくなる
基本版が最高であるべきで、追加機能が有料であるべきだ。境界線が少し 妙な場所 にある気がする
引用された文はやや不正確で、プロデューサーの生存追跡自体は同じで、違いは 孤立ジョブの復旧方法 だけだ
Python にある BI/ML/DS ワークフローが Elixir に移ってくれたらいいのにと思う。
関数型・耐障害性・並行性 に優れた Elixir のほうが、こうした作業の基盤としてはずっと自然だと思う
この動画 と Elixir Genius ガイド が良い参考資料になる
うちの会社でも Celery を使っているが、あまり良くない。Temporal は重すぎるし、Oban は軽くて気に入っている。
両方使ったことがある人の比較を聞いてみたい
Temporal はワークフロー保証とその複雑さを受け入れられる組織(たとえば銀行)に向いている。
Oban は DB ベースのキューで、信頼性は自分で強化する必要がある。
私は両方が同じシステム内に共存しているのが理想だと思う
シンプルな ProcessWorker と ECS ワーカーを組み合わせて使っている
最近の Celery は以前より不安定になったり、扱いづらくなったりしているのだろうか
興味深いプロジェクトだ。ただし、コア機能の一部が Pro 限定なのが目につく。
Postgres ベースの耐久性ワークフローを OSS で実装した先行プロジェクトとしては、DBOS と Absurd がある。
データベース中心のアプローチが増えているのは喜ばしいことだ
完全なオープンソースモデルとサポート販売だけで運営するのは 夢のようなモデル だ。いつか実現できればと思う
Postgres で数億件のジョブを処理できるほど 性能は十分なのか 気になる。以前 Redis + Sidekiq に移行したとき、大きな性能向上を見た
OSS 版は長時間ジョブがあると、プロデューサーが生きていても誤って復旧されることがあるという。
では短いジョブしか使えないということ?
正常終了を待てなかった場合にのみ、復旧タイミングが変わる