celery とは
セロリ。python job queue 処理のフレームワーク。worker daemon を待機させて async 処理の仕組みを作ったり、beat daemon を起動して定時バッチ処理を組んだりする。ドキュメントはよく整備されている。
- RDBよりも効率よく
- backend は rabbitmq cluster や redis cluster を使う。RDB 使えるけど使わないのが best practice
- job の流量制御は変更しやすいようにと考えられている
- worker daemon 起動。一台に複数起動してもよし。クラスター分散させて起動してもよし。
- job 依頼側と受け手側の両方が python で共通ライブラリ使うとかだと、どんぴしゃ
処理フロー的には AWS lambda や IBM bluemix OpenWhisk みたいな処理部分に、タスクスケジューラがついたものと考えても近い。API 定義とか気にせず処理分割を進められるのはありがたい。
worker
async job を使いたい場合は、worker daemon を起動させる。
celery -A proj worker でデーモン起動させるのだけど、proj の指定方法がわかりにくい!
ざっくりルールはこんな感じ。
- カレントディレクトリと module 検索パスを検査対象として、Celery instance を探す
-
projの文字列中に:があるとmodname:varnameが Celery instance に違いない -
proj.appがモジュールでなければ Celery instance に違いない(おいおい) -
proj.celeryがモジュールでなければ Celery instance に違いない(うーむ) -
proj.celeryがモジュールなら-
proj.celery.appがモジュールでなければ Celery instance に違いない(おいおい) -
proj.celery.celeryがモジュールでなければ Celery instance に違いない(うーむ) -
proj.celery内の変数に Celery のサブクラスインスタンスが無いか調べる
-
-
proj内の変数に Celery のサブクラスインスタンスが無いか調べる
つまり例示すると…
- カレントディレクトリにある
somename.pyファイルに
Celery instance の変数 x が存在する場合-
celery -A somename:x workerで起動する。あるいは -
celery -A somename workerでも起動できる。
-
- カレントディレクトリから見て
somename/__init__.pyファイルに
Celery instance の変数 x が存在すれば-
celery -A somename worker:xで起動する。あるいは -
celery -A somename workerでも起動できる。
-
- カレントディレクトリから見て
somename/__init__.pyが存在し、
somename/celery.pyファイルに Celery instance の変数 x が存在すれば-
celery -A somename.celery:x workerで起動する。あるいは -
celery -A somename.celery workerで起動する。あるいは -
celery -A somename workerで起動する。 -
from __future__ import absolute_importを使うべし(python 2)
-
- カレントディレクトリから見て
somename/__init__.pyが存在し、
somename/subname.pyファイルに Celery instance の変数 x が存在すれば-
celery -A somename.subname:x workerで起動する。あるいは -
celery -A somename.subname workerで起動する。
-
- モジュール検索パスの
somenameのモジュールにapp変数が存在すれば、それを Celery instance だと思い込む。-
celery -A somename:app workerで起動する。 -
celery -A somename workerで起動する。
-
- モジュール検索パスの
somenameのモジュールに Celery instance の変数 x が存在すれば-
celery -A somename:x workerで起動する。 -
celery -A somename workerで起動する。
-
- モジュール検索パスの
somename.celeryがロードできて、その中に Celery instance の変数 x が存在すれば-
celery -A somename.celery:x workerで起動する -
celery -A somename.celery workerで起動する。 -
celery -A somename workerで起動する。 -
from __future__ import absolute_importを使うべし(python 2)
-
注意深く見ていると、パターンによって app の表示が少し変わる。
celery -A somename worker
...
- ** ---------- [config]
- ** ---------- .> app: __main__:0x106a950
celery -A somename worker
...
- ** ---------- [config]
- ** ---------- .> app: somename:0x1585410
ややこしい元凶は proj.app と proj.celery という特殊ルール。
極端にややこしいケースは Flask のドキュメント で説明がないところ。Flask は一般的には Flask instance な app 変数を作る。ところが celery も app 変数が見つかればCelery instance に違いないと思い込むので、食い違いが起こる。
回避策は例えばこのようになる:
- Flask instance の変数名を
app以外にする -
:付きの文字列で指定するcelery -A your_application:celery worker
beat
定時 batch を組みたいときは beat な daemon を起動させる。
celery -A somename beat
worker daemon とは別に起動させる。こちらは基本的にはスケールアウトしないので、注意して使わないといけない。
スケジュールの設定もプログラムには埋め込めず、基本設定ファイルに列挙することになるのも注意。
ところで
job queue とセロリの関係がよくわからない…そういうイメージなの…?
追記 : 今なら kafka + faust という選択肢もありますぞ。