セロリは例外を適切に処理していないようです。
タスクがある場合:
def errorTest():
raise Exception()
そして私は電話します
r = errorTest.delay()
In [8]: r.result
In [9]: r.state
Out[9]: 'PENDING'
そして、このように無期限にハングアップします。
ログに移動して確認すると、タスクでエラーISがスローされます(そして、メッセージが必要な場合は尋ねます)と表示されます。他のタスクが原因で、バックエンドとすべてが適切に設定されていることがわかります。ちょうど働き、結果を正しく返します。
セロリで例外をキャッチするために必要なファンキーなものはありますか?
/ Celeryのバージョンは3.0.13、ブローカーはローカルマシンで実行されているRabbitMQです。
on_failure
Task
サブクラスの関数で正しく処理します。何が起こったのかを調べるだけの場合は、セットアップできます error email notifications これにより、セロリの構成でスタックトレースが送信されます。
注:v4 Celeryの時点では メールの送信をサポートするようになりました 。
CELERY_ALWAYS_EAGERをTrueに設定してCeleryを実行している場合は、次の行も設定に含めてください。
CELERY_EAGER_PROPAGATES_EXCEPTIONS = True
http://docs.celeryproject.org/en/latest/configuration.html#celery-eager-propagates-exceptions
@primalpythonの回答をより明確にする予定です。
これは失敗します:
@task
def error():
raise Exception
入出力:
In [7]: r = error.delay()
In [8]: print r.state
Out[8]: 'PENDING'
In [9]: print r.result
Out[9]: None
これは成功します:
@task
def error():
raise Exception
def on_failure(self, *args, **kwargs):
pass
入出力:
In [7]: r = error.delay()
In [8]: print r.state
Out[8]: 'FAILURE'
In [9]: print r.result
Out[9]: Exception()
IMOを使用する最も簡単な方法は、新しいCeleryアプリケーションを作成するときに使用するタスククラスへの参照を渡すことです。
1つのモジュールで、デフォルトで使用するタスククラスを定義します。
from celery.app.task import Task
import logging
logger=logging.getLogger(__name__)
class LoggingTask(Task):
def on_failure(self, exc, task_id, args, kwargs, einfo):
kwargs={}
if logger.isEnabledFor(logging.DEBUG):
kwargs['exc_info']=exc
logger.error('Task % failed to execute', task_id, **kwargs)
super().on_failure(exc, task_id, args, kwargs, einfo)
アプリを定義するときに、モジュールを参照します(注、これは指定した文字列参照です)。
from celery import Celery
app=Celery('my_project_name', task_cls='task_package.module_name:LoggingTask')
それ以降、特にタスククラスが指定されていない場合、LoggingTaskが使用されます。これにより、それぞれを変更する必要がなく、all既存のタスク(デフォルトを使用)を実行できます。これは、@ shared_taskデコレータを通常どおり使用できることも意味します。