概要
- Oban はElixir・Python両方に実装があり、ジョブ管理の中核的存在
- Oban-py はPostgreSQLベースでジョブを管理し、通知や並列処理が特徴
- OSS版とPro版で 並列処理・機能差 が存在
- ジョブ投入から実行・完了までの 内部フロー を詳細解説
- リーダー選出・孤立ジョブ救済・古いジョブの自動削除 などのバックグラウンド処理も充実
Oban-pyの概要とElixir版との比較
- Oban はElixirで長く使われてきたジョブ管理ツール、Python実装も登場
- データベースのみ でジョブ投入・実行を完結できる設計
- ユーザー作成などと同じトランザクションでジョブ投入が可能、失敗時はロールバック
- キューごとの同時実行数制御 や、完了ジョブの履歴保存・結果保存も可能
- cronスケジューリング やジョブ実行制御機能を標準搭載
- OSS版(Oban-py)と商用版(Oban-py-pro)を提供
- OSSは シングルスレッドasyncio、 バルク操作非対応、 レスキュー精度低め など制限あり
- Pro版は プロセスプール で真の並列処理、バルク操作、スマートな監視・ユニークジョブなど追加
- OSS版は小規模・評価用途に最適、スケールするならPro版推奨
ジョブ投入から実行までの流れ
- ジョブ関数定義と投入
@job(queue="default")デコレータでジョブ定義、enqueueで投入
- データベースにジョブをINSERT、stateは
available - PostgreSQLのNOTIFY で全ノードに通知、各ノードのStagerが起動
- ノードごとに担当キューが異なり、対象キューのみ反応
- Producerがイベント受信、asyncio.Eventで待機解除
- ジョブ取得時にFOR UPDATE SKIP LOCKED を利用
- 他Producerとの競合時もロック済みジョブをスキップし高速並列化
- 取得ジョブの状態をexecutingに変更し、asyncタスクとして実行
- add_done_callbackで完了時コールバック を登録、成功失敗問わず処理
- Executorがジョブ関数を解決し実行、結果をパターンマッチ
- Exceptionならリトライや破棄、Cancelならキャンセル、Snoozeなら再スケジュール、正常なら完了
- 完了ジョブはバッチでACK、次のジョブ取得へ
並列処理とPro版の違い
- OSS版は asyncioの協調並列 のみ、CPUバウンドな処理はブロック
- Pro版は プロセスプール でマルチコア並列処理が可能、特別な設定不要
- バルクインサート/ACKもPro版のみ対応
バックグラウンドプロセス
- リーダー選出
- クラスタ内で1ノードのみがジョブの掃除や救済を担当
- PostgreSQLのINSERT ... ON CONFLICT + TTLで シンプルなリーダー選出
- リーダーは定期的にリースを更新、ダウン時は自動で他ノードに引き継ぎ
- 孤立ジョブ救済(Lifeline)
- Workerやコンテナクラッシュ時、
executing状態で長時間放置されたジョブを救済 - OSS版は 時間ベース のみで判定、長時間ジョブは二重実行リスク有
- rescue_afterは最大ジョブ実行時間より長く設定推奨、ワーカーは 冪等性 が必須
- Workerやコンテナクラッシュ時、
- Pruner(古いジョブの自動削除)
- 完了・キャンセル・破棄済みジョブをmax_ageより古いものから順次削除
- LIMIT指定でテーブル肥大防止とパフォーマンス維持
まとめ・今後の展望
- Oban-pyはPostgreSQLだけで堅牢なジョブ管理 を実現
- Elixir版の思想をPythonでも忠実に再現
- Pro版でさらに高機能・高性能な運用が可能
- シンプルな設計とPostgreSQL活用 で外部依存を最小化
- 今後は エラー処理・リトライ・定期ジョブ なども深掘り予定