web-dev-qa-db-fra.com

Récupérer la liste des tâches d'une file d'attente dans le céleri

Comment puis-je récupérer une liste de tâches dans une file d'attente qui doivent encore être traitées?

109
bradley.ayers

EDIT: Voir les autres réponses pour obtenir une liste de tâches dans la file d'attente.

Vous devriez regarder ici: Guide de céleri - Inspecter les travailleurs

Fondamentalement ceci:

>>> from celery.task.control import inspect

# Inspect all nodes.
>>> i = inspect()

# Show the items that have an ETA or are scheduled for later processing
>>> i.scheduled()

# Show tasks that are currently active.
>>> i.active()

# Show tasks that have been claimed by workers
>>> i.reserved()

En fonction de ce que vous voulez

149
semarj

si vous utilisez rabbitMQ, utilisez ceci dans terminal:

Sudo rabbitmqctl list_queues

il imprimera la liste des files d'attente avec le nombre de tâches en attente. par exemple:

Listing queues ...
0b27d8c59fba4974893ec22d478a7093    0
0e0a2da9828a48bc86fe993b210d984f    0
[email protected] 0
11926b79e30a4f0a9d95df61b6f402f7    0
15c036ad25884b82839495fb29bd6395    1
[email protected]    0
celery  166
celeryev.795ec5bb-a919-46a8-80c6-5d91d2fcf2aa   0
celeryev.faa4da32-a225-4f6c-be3b-d8814856d1b6   0

le nombre dans la colonne de droite est le nombre de tâches dans la file d'attente. ci-dessus, la file de céleri a 166 tâches en attente.

37
Ali

Si vous n'utilisez pas de tâches hiérarchisées, c'est assez simple si vous utilisez Redis. Pour que la tâche compte:

redis-cli -h Host -p PORT -n DATABASE_NUMBER llen QUEUE_NAME

Cependant, les tâches classées par ordre de priorité utilisent une clé différente dans redis ; L'image complète est que vous devez interroger redis pour chaque priorité de tâche. En python (et du projet Flower), cela ressemble à:

PRIORITY_SEP = '\x06\x16'
DEFAULT_PRIORITY_STEPS = [0, 3, 6, 9]


def make_queue_name_for_pri(queue, pri):
    """Make a queue name for redis

    Celery uses PRIORITY_SEP to separate different priorities of tasks into
    different queues in Redis. Each queue-priority combination becomes a key in
    redis with names like:

     - batch1\x06\x163 <-- P3 queue named batch1

    There's more information about this in Github, but it doesn't look like it 
    will change any time soon:

      - https://github.com/celery/kombu/issues/422

    In that ticket the code below, from the Flower project, is referenced:

      - https://github.com/mher/flower/blob/master/flower/utils/broker.py#L135

    :param queue: The name of the queue to make a name for.
    :param pri: The priority to make a name with.
    :return: A name for the queue-priority pair.
    """
    if pri not in DEFAULT_PRIORITY_STEPS:
        raise ValueError('Priority not in priority steps')
    return '{0}{1}{2}'.format(*((queue, PRIORITY_SEP, pri) if pri else
                                (queue, '', '')))


def get_queue_length(queue_name='celery'):
    """Get the number of tasks in a celery queue.

    :param queue_name: The name of the queue you want to inspect.
    :return: the number of items in the queue.
    """
    priority_names = [make_queue_name_for_pri(queue_name, pri) for pri in
                      DEFAULT_PRIORITY_STEPS]
    r = redis.StrictRedis(
        Host=settings.REDIS_Host,
        port=settings.REDIS_PORT,
        db=settings.REDIS_DATABASES['CELERY'],
    )
    return sum([r.llen(x) for x in priority_names])

Si vous voulez obtenir une tâche réelle, vous pouvez utiliser quelque chose comme:

redis-cli -h Host -p PORT -n DATABASE_NUMBER lrange QUEUE_NAME 0 -1

De là, vous devrez désérialiser la liste renvoyée. Dans mon cas, j'ai pu accomplir cela avec quelque chose comme:

r = redis.StrictRedis(
    Host=settings.REDIS_Host,
    port=settings.REDIS_PORT,
    db=settings.REDIS_DATABASES['CELERY'],
)
l = r.lrange('celery', 0, -1)
pickle.loads(base64.decodestring(json.loads(l[0])['body']))

Sachez simplement que la désérialisation peut prendre un moment, et que vous aurez besoin d’ajuster les commandes ci-dessus pour gérer différentes priorités.

14
mlissner

Pour récupérer des tâches depuis le backend, utilisez cette

from amqplib import client_0_8 as amqp
conn = amqp.Connection(Host="localhost:5672 ", userid="guest",
                       password="guest", virtual_Host="/", insist=False)
chan = conn.channel()
name, jobs, consumers = chan.queue_declare(queue="queue_name", passive=True)
10
ashish

Le module d’inspection du céleri semble ne connaître que les tâches du point de vue des travailleurs. Si vous voulez voir les messages qui sont dans la file (que les travailleurs doivent encore extraire), je suggère d'utiliser pyrabbit , qui peut s’interfacer avec l’API http Rabbitmq pour récupérer toutes sortes d’informations dans la file.

Un exemple peut être trouvé ici: Récupérer la longueur de la file d’attente avec Celery (RabbitMQ, Django)

4
Paul in 't Hout

Une solution copier/coller pour Redis avec sérialisation json:

def get_celery_queue_items(queue_name):
    import base64
    import json  

    # Get a configured instance of a celery app:
    from yourproject.celery import app as celery_app

    with celery_app.pool.acquire(block=True) as conn:
        tasks = conn.default_channel.client.lrange(queue_name, 0, -1)
        decoded_tasks = []

    for task in tasks:
        j = json.loads(task)
        body = json.loads(base64.b64decode(j['body']))
        decoded_tasks.append(body)

    return decoded_tasks

Cela fonctionne avec Django. N'oubliez pas de changer yourproject.celery.

4
Max Malysh

Je pense que le seul moyen d'obtenir les tâches en attente est de conserver une liste des tâches que vous avez commencées et de laisser la tâche se supprimer d'elle-même au début.

Avec rabbitmqctl et list_queues, vous pouvez avoir un aperçu du nombre de tâches en attente, mais pas des tâches proprement dites: http://www.rabbitmq.com/man/rabbitmqctl.1.man.html

Si ce que vous voulez inclut la tâche en cours de traitement, mais ne sont pas encore terminés, vous pouvez conserver une liste de vos tâches et vérifier leur état:

from tasks import add
result = add.delay(4, 4)

result.ready() # True if finished

Vous pouvez également laisser Celery stocker les résultats avec CELERY_RESULT_BACKEND et vérifier quelles tâches ne figurent pas dans cette liste.

3
Sebastian Blask

Pour autant que je sache, Celery ne fournit pas d'API pour examiner les tâches en attente. Ceci est spécifique au courtier. Si vous utilisez Redis comme exemple de courtier, l'examen des tâches en attente dans la file d'attente celery (par défaut) est aussi simple que:

  1. se connecter à la base de données du courtier
  2. lister les éléments dans la liste celery (commande LRANGE pour un exemple)

N'oubliez pas que ces tâches doivent être sélectionnées par les employés disponibles. Votre cluster peut avoir certaines tâches en cours d'exécution - celles-ci ne seront pas dans cette liste car elles ont déjà été sélectionnées.

2
DejanLekic
from celery.task.control import inspect
def key_in_list(k, l):
    return bool([True for i in l if k in i.values()])

def check_task(task_id):
    task_value_dict = inspect().active().values()
    for task_list in task_value_dict:
        if self.key_in_list(task_id, task_list):
             return True
    return False
1
张朝龙

Si vous utilisez Celery + Django le moyen le plus simple d'inspecter des tâches à l'aide de commandes directement à partir de votre terminal dans votre environnement virtuel ou à l'aide d'un chemin complet de céleri

Doc: http://docs.celeryproject.org/en/latest/userguide/workers.html?highlight=revoke#inspecting-workers

$ celery inspect reserved
$ celery inspect inspect
$ celery inspect registered
$ celery inspect scheduled

De même, si vous utilisez Celery + RabbitMQ vous pouvez inspectez la liste des files d'attente à l'aide de la commande suivante:

Plus d'info: https://linux.die.net/man/1/rabbitmqctl

$ Sudo rabbitmqctl list_queues
1
om2c0de

J'en suis venu à la conclusion que le meilleur moyen d'obtenir le nombre de travaux en file d'attente est d'utiliser rabbitmqctl comme cela a été suggéré à plusieurs reprises ici. Pour permettre à n'importe quel utilisateur choisi d'exécuter la commande avec Sudo, j'ai suivi les instructions here (j'ai sauté la modification de la partie du profil car cela ne me dérange pas de taper Sudo avant la commande.)

J'ai également récupéré les extraits grep et cut de jamesc et les ai intégrés à des appels de sous-processus. 

from subprocess import Popen, PIPE
p1 = Popen(["Sudo", "rabbitmqctl", "list_queues", "-p", "[name of your virtula Host"], stdout=PIPE)
p2 = Popen(["grep", "-e", "^celery\s"], stdin=p1.stdout, stdout=PIPE)
p3 = Popen(["cut", "-f2"], stdin=p2.stdout, stdout=PIPE)
p1.stdout.close()
p2.stdout.close()
print("number of jobs on queue: %i" % int(p3.communicate()[0]))
1
Peter Shannon

Avec subprocess.run:

import subprocess
import re
active_process_txt = subprocess.run(['celery', '-A', 'my_proj', 'inspect', 'active'],
                                        stdout=subprocess.PIPE).stdout.decode('utf-8')
return len(re.findall(r'worker_pid', active_process_txt))

Veillez à changer my_proj avec your_proj

0
sashaboulouds

Si vous contrôlez le code des tâches, vous pouvez contourner le problème en laissant une tâche déclencher une nouvelle tentative triviale lors de la première exécution, puis en vérifiant inspect().reserved(). La nouvelle tentative enregistre la tâche avec le résultat final et le céleri peut le voir. La tâche doit accepter self ou context en tant que premier paramètre pour que nous puissions accéder au nombre de tentatives.

@task(bind=True)
def mytask(self):
    if self.request.retries == 0:
        raise self.retry(exc=MyTrivialError(), countdown=1)
    ...

Cette solution est agnostique auprès des courtiers, c.-à-d. vous n'avez pas à vous demander si vous utilisez RabbitMQ ou Redis pour stocker les tâches.

EDIT: après les tests, j'ai trouvé que ce n'était qu'une solution partielle. La taille de reserved est limitée au paramètre de prélecture pour le travailleur.

0
hedleyroos

lancement de la fleur - spectateur des tâches de selery

celery -A app.celery flower

puis ouvrez dans le navigateur

localhost:5555
0