ある状況下では、セロリのタスクをそのタスク内から失敗させたいと思います。私は以下を試しました:
from celery.task import task
from celery import states
@task()
def run_simulation():
if some_condition:
run_simulation.update_state(state=states.FAILURE)
return False
ただし、タスクは引き続き成功したと報告します。
タスクsim.tasks.run_simulation [9235e3a7-c6d2-4219-bbc7-acf65c816e65]は1.17847704887で成功しました:False
状態は、タスクの実行中にのみ変更できるようで、タスクが完了すると、セロリは状態を結果と見なすものに変更します( この質問 を参照)。例外を発生させてタスクを失敗させずに、タスクが失敗したことをセロリに返す方法はありますか?
Ask Solemからこの質問に対して 興味深い回答 を受け取りました。彼は問題を解決するために「after_return」ハンドラーを提案しています。これは将来的に興味深いオプションになるかもしれません。
それまでの間、タスクを失敗させたいときにタスクから文字列 'FAILURE'を返すだけで問題を解決し、次のようにチェックしました。
result = AsyncResult(task_id)
if result.state == 'FAILURE' or (result.state == 'SUCCESS' and result.get() == 'FAILURE'):
# Failure processing task
例外を発生させずにタスクを失敗としてマークするには、タスクの状態をFAILURE
に更新してから、Ignore
例外を発生させます。これは、値を返すとタスクが成功したと記録されるためです。例:
from celery import Celery, states
from celery.exceptions import Ignore
app = Celery('tasks', broker='amqp://guest@localhost//')
@app.task(bind=True)
def run_simulation(self):
if some_condition:
# manually update the task state
self.update_state(
state = states.FAILURE,
meta = 'REASON FOR FAILURE'
)
# ignore the task so no other state is recorded
raise Ignore()
ただし、最善の方法は、タスクから例外を発生させることです。カスタム例外を作成して、これらの失敗を追跡できます。
class TaskFailure(Exception):
pass
そして、あなたのタスクからこの例外を発生させます:
if some_condition:
raise TaskFailure('Failure reason')
提案された解決策を使用していくつかの問題が発生したので、ピエールの答えをさらに拡張したいと思います。
タスクの状態をstates.FAILUREに更新するときにカスタムフィールドを許可するには、FAILURE状態が持ついくつかの属性をモックすることも重要です(exc_typeとexc_messageに注意してください)。ソリューションがタスクを終了している間、状態をクエリしようとすると(例-「REASONFORFAILURE」値をフェッチする)は失敗します。
以下は私が引用した参照用のスニペットです: https://www.distributedpython.com/2018/09/28/celery-task-states/
@app.task(bind=True)
def task(self):
try:
raise ValueError('Some error')
except Exception as ex:
self.update_state(
state=states.FAILURE,
meta={
'exc_type': type(ex).__name__,
'exc_message': traceback.format_exc().split('\n')
'custom': '...'
})
raise Ignore()