簡體   English   中英

在 Celery 中檢索隊列中的任務列表

[英]Retrieve list of tasks in a queue in Celery

如何檢索隊列中尚未處理的任務列表?

編輯:查看其他答案以獲取隊列中的任務列表。

你應該看這里: 芹菜指南 - 檢查工人

基本上是這樣的:

my_app = Celery(...)

# Inspect all nodes.
i = my_app.control.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()

取決於你想要什么

如果您使用的是 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

右列的數字是隊列中的任務數。 在上面,celery 隊列有 166 個待處理的任務。

如果您使用Celery+Django直接從虛擬環境中的終端使用命令或使用 celery 的完整路徑來檢查任務的最簡單方法:

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

如果您不使用優先任務,那么如果您使用 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']))

請注意,反序列化可能需要一些時間,您需要調整上面的命令以處理各種優先級。

要從后端檢索任務,請使用此

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)

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

這在我的應用程序中對我有用:

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

celery inspect 模塊似乎只從工人的角度了解任務。 如果您想查看隊列中的消息(尚未被工作人員拉取),我建議使用pyrabbit ,它可以與 rabbitmq http api 接口以從隊列中檢索各種信息。

一個例子可以在這里找到: Retrieve queue length with Celery (RabbitMQ, Django)

我認為獲取正在等待的任務的唯一方法是保留您啟動的任務列表,並讓任務在啟動時從列表中刪除。

使用 rabbitmqctl 和 list_queues,您可以大致了解有多少任務正在等待,但不是任務本身: http ://www.rabbitmq.com/man/rabbitmqctl.1.man.html

如果您想要的包括正在處理的任務,但尚未完成,您可以保留您的任務列表並檢查它們的狀態:

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

result.ready() # True if finished

或者你讓 Celery 用 CELERY_RESULT_BACKEND 存儲結果並檢查你的哪些任務不在那里。

據我所知,Celery 沒有提供用於檢查隊列中等待任務的 API。 這是特定於經紀人的。 例如,如果您使用 Redis 作為代理,那么檢查在celery (默認)隊列中等待的任務非常簡單:

  1. 連接到代理
  2. 列出celery列表中的項目(例如 LRANGE 命令)

請記住,這些是等待可用工人挑選的任務。 您的集群可能正在運行一些任務 - 這些任務不會在此列表中,因為它們已經被選中。

在特定隊列中檢索任務的過程是特定於代理的。

我得出的結論是,獲得隊列中作業數量的最佳方法是使用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]))

如果您控制任務的代碼,那么您可以通過讓任務在第一次執行時觸發微不足道的重試,然后檢查inspect().reserved() 重試向結果后端注冊任務,芹菜可以看到這一點。 任務必須接受selfcontext作為第一個參數,以便我們可以訪問重試計數。

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

該解決方案與經紀人無關,即。 您不必擔心是使用 RabbitMQ 還是 Redis 來存儲任務。

編輯:經過測試,我發現這只是部分解決方案。 保留的大小僅限於工作程序的預取設置。

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

發射花 - 查看selery任務

celery -A app.celery flower

然后在瀏覽器中打開

localhost:5555

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

小心用your_proj更改my_proj

要獲取隊列中的任務數,您可以使用庫,這是一個簡化的示例:

from flower.utils.broker import Broker
from django.conf import settings

def get_queue_length(queue):
    broker = Broker(settings.CELERY_BROKER_URL)
    queues_result = broker.queues([queue])
    return queues_result.result()[0]['messages']

下面是一個代碼示例,用於檢索 Celery 隊列中的任務列表:

import celery

celery_object = celery.Celery()
inspector = celery.current_app.control.inspect()
result = inspector.active()

# Print the list of tasks
print(result)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM