Celeryのキューにあるタスクのリストを取得する


147

まだ処理されていないキュー内のタスクのリストを取得するにはどうすればよいですか?


1
RabbitMQですが、Python内でこのリストを取得したいと考えています。
bradley.ayers 2011

回答:


174

編集:キュー内のタスクのリストを取得するための他の回答を参照してください。

ここを見てください: セロリガイド-労働者の検査

基本的にこれ:

from celery.app.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()

あなたが望むものに応じて


9
私はそれを試しましたが、それは本当に遅いです(1秒のように)。トルネードアプリで進捗状況を監視するために同期して使用しているため、高速でなければなりません。
JulienFr 2013

41
これにより、まだ処理されていないキュー内のタスクのリストは返されません。
Ed J

9
i.reserved()キューに入れられたタスクのリストを取得するために使用します。
バナナ2014年

4
i.reserved()がアクティブなタスクの正確なリストを持たないことを経験した人はいますか?リストに表示されないタスクを実行しています。私はdjango-celery == 3.1.10にいます
Seperman

6
ワーカーを指定するとき、引数としてリストを使用する必要がありました:inspect(['celery@Flatty'])。速度が大幅に向上しましたinspect()
Adversus

42

rabbitMQを使用している場合は、これをターミナルで使用します。

sudo rabbitmqctl list_queues

保留中のタスクの数を含むキューのリストを出力します。例えば:

Listing queues ...
0b27d8c59fba4974893ec22d478a7093    0
0e0a2da9828a48bc86fe993b210d984f    0
10@torob2.celery.pidbox 0
11926b79e30a4f0a9d95df61b6f402f7    0
15c036ad25884b82839495fb29bd6395    1
celerey_mail_worker@torob2.celery.pidbox    0
celery  166
celeryev.795ec5bb-a919-46a8-80c6-5d91d2fcf2aa   0
celeryev.faa4da32-a225-4f6c-be3b-d8814856d1b6   0

右の列の数字は、キュー内のタスクの数です。上記では、セロリキューには166の保留中のタスクがあります。


1
私はsudo権限を持っているときにこれに精通していますが、権限のないシステムユーザーがチェックできるようにしたいのですが、何か提案はありますか?
セージ

さらに、この数値をパイプ処理して、後でその数値を処理する場合は統計情報などgrep -e "^celery\s" | cut -f2を抽出166できます。
jamesc 2017年

21

優先タスクを使用しない場合、Redisを使用している場合、これは実際には非常に簡単です。タスク数を取得するには:

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

ただし、優先タスクはredis別のキーを使用するため、全体像は少し複雑になります。全体像は、タスクのすべての優先度についてredisをクエリする必要があるということです。Python(およびFlowerプロジェクト)では、次のようになります。

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

実際のタスクを取得したい場合は、次のようなものを使用できます。

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

そこから、返されたリストを逆シリアル化する必要があります。私の場合、私はこれを次のようなもので達成することができました:

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']))

逆シリアル化には少し時間がかかる可能性があることに注意してください。さまざまな優先順位で機能するには、上記のコマンドを調整する必要があります。


これを本番環境で使用した後、Celeryの設計が原因で、優先タスクを使用する失敗することがわかりました。
mlissner 2017年

1
上記を更新して、優先タスクを処理できるようにしました。進捗!
mlissner

1
ただ、物事を綴るために、DATABASE_NUMBERデフォルトで使用があり0、そしてQUEUE_NAMEあるceleryので、redis-cli -n 0 llen celeryキューに入れられたメッセージの数を返します。
Vineet Bansal

私のセロリの場合、キューの名前はでは'{{{0}}}{1}{2}'なくです'{0}{1}{2}'。それ以外は、これは完璧に機能します!
zupo

12

バックエンドからタスクを取得するには、これを使用します

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)

2
しかし、「ジョブ」はキューにあるタスクの数のみを示します
bitnik

タスクの名前を示す関連する回答については、stackoverflow.com / a / 57807913/9843399を参照してください。
Caleb Syring

10

あなたが使用している場合はセロリ+ Djangoのあなたにあなたの端末から直接コマンドを使用してタスクを検査する最も簡単な方法は、仮想環境をまたは使用して完全なパスをセロリました:

ドキュメントhttp : //docs.celeryproject.org/en/latest/userguide/workers.html?highlight=revoke#inspecting-workers

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

また、Celery + RabbitMQを使用している場合は、キューのリストを検査できます、次のコマンドを使用して。

詳細https : //linux.die.net/man/1/rabbitmqctl

$ sudo rabbitmqctl list_queues

4
明確なプロジェクトがある場合は、次を使用できますcelery -A my_proj inspect reserved
sashaboulouds

6

jsonシリアル化を使用したRedisのコピーと貼り付けのソリューション:

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

Djangoで動作します。変更することを忘れないでくださいyourproject.celery


1
ピクルシリアライザーを使用している場合は、body =行をに変更できますbody = pickle.loads(base64.b64decode(j['body']))
ジムハンジカー

4

セロリ検査モジュールは、作業者の観点からのみタスクを認識しているようです。キューにあるメッセージを表示したい場合は(まだワーカーによってプルされます)pyrabbitを使用することをお勧めしますは、rabbitmq http apiとやり取りしてキューからあらゆる種類の情報を取得できるます。

例はここにあります: Celeryを使用してキューの長さを取得する(RabbitMQ、Django)


3

待機中のタスクを取得する唯一の方法は、開始したタスクのリストを保持し、開始時にタスクをリストから削除させることだと思います。

rabbitmqctlとlist_queuesを使用すると、待機しているタスクの数の概要を取得できますが、タスク自体は取得できません。 。http

必要なものが処理中のタスクを含んでいるが、まだ完了していない場合は、タスクのリストを保持し、それらの状態を確認できます。

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

result.ready() # True if finished

または、CeleryにCELERY_RESULT_BACKENDを使用して結果を保存させ、そこにないタスクを確認します。


3

これは私のアプリケーションで私のために働きました:

def get_celery_queue_active_jobs(queue_name):
    connection = <CELERY_APP_INSTANCE>.connection()

    try:
        channel = connection.channel()
        name, jobs, consumers = channel.queue_declare(queue=queue_name, passive=True)
        active_jobs = []

        def dump_message(message):
            active_jobs.append(message.properties['application_headers']['task'])

        channel.basic_consume(queue=queue_name, callback=dump_message)

        for job in range(jobs):
            connection.drain_events()

        return active_jobs
    finally:
        connection.close()

active_jobs キュー内のタスクに対応する文字列のリストになります。

CELERY_APP_INSTANCEを自分のものに置き換えることを忘れないでください。

ここで彼の答えで私を正しい方向に向けてくれた@ashishに感謝します:https://stackoverflow.com/a/19465670/9843399


私の場合jobsは常にゼロです...何か考えはありますか?
daveoncode

@daveoncode役立つ情報を提供するのに十分な情報だとは思いません。あなた自身の質問を開くことができます。Pythonで情報を取得することを指定した場合、これが重複することはないと思います。私はstackoverflow.com/a/19465670/9843399に戻ります。これは私が私の答えに基づいたものであり、それが最初に機能することを確認します。
Caleb Syring

@CalebSyringこれは、キューに入れられたタスクを本当に示す最初のアプローチです。非常に素晴らしい。私にとっての唯一の問題は、リストの追加が機能していないように見えることです。コールバック関数にリストに書き込む方法を教えてください。
Varlor

@バラー申し訳ありませんが、誰かが私の回答を不適切に編集しました。編集履歴で元の回答を探すことができます。私はこれを修正するために取り組んでいます。(編集:行って編集を拒否したところ、明らかなpythonエラーが発生しました。これで問題が解決したかどうかをお知らせください。)
Caleb Syring

@CalebSyringクラスの属性として機能するリストを使用して、クラスでコードを使用しました!
Varlor

2

私の知る限り、Celeryはキューで待機しているタスクを検査するためのAPIを提供していません。これはブローカー固有です。例としてブローカーとしてRedisを使用する場合、celery(デフォルトの)キューで待機しているタスクの検査は次のように簡単です。

  1. ブローカーデータベースに接続する
  2. リスト内のリスト項目celery(例としてはLRANGEコマンド)

これらは、利用可能なワーカーによって選択されるのを待っているタスクであることに注意してください。クラスターでいくつかのタスクが実行されている可能性があります。これらのタスクは既に選択されているため、このリストには表示されません。


1

rabbitmqctlここで何度か提案されているように、キューにあるジョブの数を取得する最良の方法は使用するという結論に達しました。選択したユーザーがコマンドを実行できるようにするsudoには、ここの指示に従いまし(コマンドの前にsudoを入力してもかまわないので、プロファイル部分の編集はスキップしました)。

また、jamesc grepcutスニペットを取得し、サブプロセス呼び出しでラップしました。

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

0

タスクのコードを制御している場合は、タスクを初めて実行するときに簡単な再試行をタスクにトリガーさせ、チェックすることで問題を回避できますinspect().reserved()。再試行はタスクを結果バックエンドに登録し、セロリはそれを見ることができます。タスクは、selfまたはcontextを再試行カウントにアクセスできるように、最初のパラメーターとして受け入れる必要があります。

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

このソリューションはブローカーにとらわれません。タスクの保存にRabbitMQを使用しているかRedisを使用しているかについて心配する必要はありません。

編集:テスト後、これは部分的なソリューションにすぎないことがわかりました。reservedのサイズは、ワーカーのプリフェッチ設定に制限されています。


0

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

と変更my_projするように注意してくださいyour_proj

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.