web-dev-qa-db-fra.com

Découvrez si la tâche de céleri existe

Est-il possible de savoir s'il existe une tâche avec un certain identifiant de tâche? Lorsque j'essaie d'obtenir le statut, je suis toujours en attente.

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

Je veux savoir si un identifiant de tâche donné est un identifiant de tâche de céleri réel et non une chaîne aléatoire. Je veux des résultats différents selon qu'il existe une tâche valide pour un certain identifiant.

Il y avait peut-être une tâche valide dans le passé avec le même identifiant, mais les résultats peuvent avoir été supprimés du backend.

37
dominik

Le céleri n'écrit pas d'état lorsque la tâche est envoyée, il s'agit en partie d'une optimisation .__ (voir http://docs.celeryproject.org/en/latest/userguide/tasks.html#state ).

Si vous en avez vraiment besoin, ajoutez simplement:

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

@after_task_publish.connect
def update_sent_state(sender=None, body=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(body['id'], None, "SENT")

Ensuite, vous pouvez tester l'état PENDING pour détecter le fait qu'une tâche n'a pas (apparemment) été envoyée:

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

AsyncResult.state renvoie PENDING en cas d'identificateur de tâche inconnu.

EN ATTENDANT 

La tâche est en attente d'exécution ou inconnue. Toute identification de tâche qui n'est pas connu est impliqué dans l'état en attente.

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

Vous pouvez fournir des identifiants de tâches personnalisés si vous devez distinguer des identifiants inconnus des existants:

>>> 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

En ce moment, j'utilise le schéma suivant:

  1. Obtenir l'identifiant de la tâche.
  2. Définissez la clé memcache comme "task_% s", message% task.id "démarré". 
  3. Transmettre l'identifiant de la tâche au client.
  4. Maintenant, à partir du client, je peux surveiller l’état de la tâche (défini à partir des messages de tâche dans memcache).
  5. De tâche en attente - définissez le message clé «Prêt» dans memcache. 
  6. Du client à la tâche prête - démarrez une tâche spéciale qui supprimera la clé de memcache et effectuera les actions de nettoyage nécessaires.
2
Nikolay Fominyh

Vous devez appeler .get() sur l'objet AsyncTask que vous créez pour extraire le résultat du backend.

Voir le Céleri FAQ .


Pour clarifier davantage ma réponse.

Toute chaîne est techniquement un identifiant valide, il n'y a aucun moyen de valider l'ID de la tâche. Le seul moyen de savoir si une tâche existe est de demander au serveur s'il en a connaissance et vous devez utiliser .get().

Cela introduit le problème que .get() bloque lorsque le système principal ne contient aucune information sur l'ID de tâche que vous avez fourni. Il s'agit d'un problème qui vous permet de démarrer une tâche et d'attendre ensuite qu'elle soit terminée.

Dans le cas de la question initiale, je vais supposer que le PO veut obtenir l'état d'une tâche précédemment terminée. Pour ce faire, vous pouvez passer un très petit délai d'attente et rattraper les erreurs de délai d'attente:

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"

Il va sans dire que cela ne fonctionne que si votre back-end stocke des résultats, sinon, il n'y a aucun moyen de savoir si un ID de tâche est valide ou non, car rien ne conserve leur enregistrement.


Encore plus de clarification.

Ce que vous voulez faire ne peut pas être accompli en utilisant le backend AMQP car il ne stocke pas les résultats, il les transmet .

Ma suggestion serait de passer à un backend de base de données afin que les résultats soient dans une base de données que vous pouvez interroger en dehors des modules de céleri existants. S'il n'y a pas de tâches dans la base de résultats, vous pouvez supposer que l'ID n'est pas valide.

0
Evan Borgstrom