web-dev-qa-db-ja.com

セロリタスクが存在するかどうかを確認する

特定のタスクIDのタスクが存在するかどうかを確認することはできますか?ステータスを取得しようとすると、常に保留になります。

>>> AsyncResult('...').status
'PENDING'

特定のタスクIDが実際のセロリタスクIDであり、ランダムな文字列ではないかどうかを知りたいです。特定のIDに対して有効なタスクがあるかどうかに応じて、異なる結果が必要です。

同じidの有効なタスクが過去にあった可能性がありますが、結果はバックエンドから削除された可能性があります。

44
dominik

Celeryはタスクの送信時に状態を書き込みません。これは一部最適化です( http://docs.celeryproject.org/en/latest/userguide/tasks.html#state を参照)。

本当に必要な場合は、簡単に追加できます。

from celery import current_app
# `after_task_publish` is available in celery 3.1+
# for older versions use the deprecated `task_sent` signal
from celery.signals import after_task_publish

# when using celery versions older than 4.0, use body instead of headers

@after_task_publish.connect
def update_sent_state(sender=None, headers=None, **kwargs):
    # the task may not exist if sent using `send_task` which
    # sends tasks by name, so fall back to the default result backend
    # if that is the case.
    task = current_app.tasks.get(sender)
    backend = task.backend if task else current_app.backend

    backend.store_result(headers['id'], None, "SENT")

次に、PENDING状態をテストして、タスクが(一見)送信されていないことを検出できます。

>>> result.state != "PENDING"
31
asksol

AsyncResult.stateは、不明なタスクIDの場合にPENDINGを返します。

保留中

タスクは実行を待機しているか、不明です。不明なタスクIDは保留状態にあることを意味します。

http://docs.celeryproject.org/en/latest/userguide/tasks.html#pending

不明なIDを既存のIDと区別する必要がある場合は、カスタムタスクIDを指定できます。

>>> from tasks import add
>>> from celery.utils import uuid
>>> r = add.apply_async(args=[1, 2], task_id="celery-task-id-"+uuid())
>>> id = r.task_id
>>> id
'celery-task-id-b774c3f9-5280-4ebe-a770-14a6977090cd'
>>> if not "blubb".startswith("celery-task-id-"): print "Unknown task id"
... 
Unknown task id
>>> if not id.startswith("celery-task-id-"): print "Unknown task id"
... 
9
mher

現在、私は次のスキームを使用しています:

  1. タスクIDを取得します。
  2. 'task_%s'%task.id message 'Started'のようなmemcacheキーに設定します。
  3. タスクIDをクライアントに渡します。
  4. これで、クライアントからタスクのステータスを監視できます(タスクメッセージからmemcacheに設定)。
  5. 準備完了のタスクから-memcacheキーメッセージ「準備完了」に設定します。
  6. タスクの準備が整ったクライアントから-memcacheからキーを削除し、必要なクリーニングアクションを実行する特別なタスクを開始します。
2
Nikolay Fominyh

バックエンドから結果を実際にフェッチするには、作成したAsyncTaskオブジェクトで.get()を呼び出す必要があります。

Celery FAQ を参照してください。


私の答えをさらに明確にするため。

文字列は技術的には有効なIDであり、タスクIDを検証する方法はありません。タスクが存在するかどうかを確認する唯一の方法は、バックエンドがそれを知っているかどうかを尋ね、.get()を使用する必要があることを確認することです。

これは、指定したタスクIDに関する情報がバックエンドにないときに.get()がブロックするという問題を引き起こします。これは、タスクを開始して完了を待機できるようにするための仕様です。

元の質問の場合、OPが以前に完了したタスクの状態を取得したいと想定します。これを行うには、非常に小さなタイムアウトを渡し、タイムアウトエラーをキャッチします。

from celery.exceptions import TimeoutError
try:
    # fetch the result from the backend
    # your backend must be fast enough to return
    # results within 100ms (0.1 seconds)
    result = AsyncResult('blubb').get(timeout=0.1)
except TimeoutError:
    result = None

if result:
    print "Result exists; state=%s" % (result.state,)
else:
    print "Result does not exist"

言うまでもなく、これはバックエンドが結果を保存している場合にのみ機能し、タスクIDが記録されていないためにタスクIDが有効かどうかを知る方法がない場合にのみ機能します。


さらに明確化。

結果を保存せず、転送する であるため、AMQPバックエンドを使用して実行することはできません。

私の提案は、データベースのバックエンドに切り替えて、結果が既存のセロリモジュールの外部でクエリできるデータベースにあるようにすることです。結果データベースにタスクが存在しない場合は、IDが無効であると想定できます。

0
Evan Borgstrom