Truy xuất danh sách các nhiệm vụ trong hàng đợi trong Celery


147

Làm cách nào tôi có thể truy xuất danh sách các tác vụ trong hàng đợi chưa được xử lý?


1
RabbitMQ, nhưng tôi muốn lấy danh sách này trong Python.
bradley.ayers

Câu trả lời:


174

EDIT: Xem các câu trả lời khác để nhận danh sách các nhiệm vụ trong hàng đợi.

Bạn nên xem tại đây: Hướng dẫn cần tây - Kiểm tra công nhân

Về cơ bản này:

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

Tùy thuộc vào những gì bạn muốn


9
Tôi đã thử nó, nhưng nó thực sự chậm (như 1 giây). Tôi đang sử dụng nó đồng bộ hóa trong một ứng dụng lốc xoáy để theo dõi tiến trình, vì vậy nó phải nhanh.
JulienFr

41
Điều này sẽ không trả về một danh sách các nhiệm vụ trong hàng đợi chưa được xử lý.
Ed J

9
Sử dụng i.reserved()để có được một danh sách các nhiệm vụ xếp hàng.
Chuối

4
Có ai có kinh nghiệm rằng i.reserved () sẽ không có một danh sách chính xác các nhiệm vụ đang hoạt động không? Tôi có các nhiệm vụ đang chạy mà không hiển thị trong danh sách. Tôi đang trên django-cần tây == 3.1.10
Seperman

6
Khi chỉ định công nhân, tôi phải sử dụng một danh sách làm đối số : inspect(['celery@Flatty']). Cải thiện tốc độ rất lớn inspect().
Adversus

42

nếu bạn đang sử dụng rabbitMQ, hãy sử dụng cái này trong terminal:

sudo rabbitmqctl list_queues

nó sẽ in danh sách các hàng đợi với số lượng tác vụ đang chờ xử lý. ví dụ:

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

số ở cột bên phải là số nhiệm vụ trong hàng đợi. ở trên, hàng đợi cần tây có 166 nhiệm vụ đang chờ xử lý.


1
Tôi quen với điều này khi tôi có các đặc quyền sudo, nhưng tôi muốn một người dùng hệ thống không có đặc quyền có thể kiểm tra - có đề xuất nào không?
hiền nhân

Ngoài ra, bạn có thể chuyển thông tin này grep -e "^celery\s" | cut -f2để trích xuất rằng 166nếu bạn muốn xử lý số đó sau, hãy nói về số liệu thống kê.
jamesc

21

Nếu bạn không sử dụng các nhiệm vụ ưu tiên, điều này thực sự khá đơn giản nếu bạn đang sử dụng Redis. Để có được nhiệm vụ:

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

Nhưng, các tác vụ ưu tiên sử dụng một khóa khác trong redis , vì vậy bức tranh đầy đủ phức tạp hơn một chút. Hình ảnh đầy đủ là bạn cần truy vấn redis cho mọi ưu tiên của nhiệm vụ. Trong python (và từ dự án Hoa), nó trông giống như:

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

Nếu bạn muốn nhận một nhiệm vụ thực tế, bạn có thể sử dụng một cái gì đó như:

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

Từ đó bạn sẽ phải giải tuần tự hóa danh sách trả về. Trong trường hợp của tôi, tôi đã có thể thực hiện điều này với một cái gì đó như:

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

Chỉ cần cảnh báo rằng khử lưu huỳnh có thể mất một chút thời gian và bạn sẽ cần điều chỉnh các lệnh trên để làm việc với các ưu tiên khác nhau.


Sau khi sử dụng điều này trong sản xuất, tôi đã biết rằng nó thất bại nếu bạn sử dụng các nhiệm vụ ưu tiên , do thiết kế của Celery.
mlissner

1
Tôi đã cập nhật ở trên để xử lý các nhiệm vụ ưu tiên. Phát triển!
mlissner

1
Chỉ cần đánh vần những điều trên, các DATABASE_NUMBERsử dụng bởi mặc định là 0, và QUEUE_NAMEcelery, do đó redis-cli -n 0 llen celerysẽ trả lại số tin nhắn xếp hàng đợi.
Vine Bansal

Đối với cần tây của tôi, tên của hàng đợi là '{{{0}}}{1}{2}'thay vì '{0}{1}{2}'. Ngoài ra, điều này hoạt động hoàn hảo!
zupo

12

Để lấy các tác vụ từ phụ trợ, hãy sử dụng

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
nhưng 'công việc' chỉ cung cấp số lượng tác vụ trong hàng đợi
bitnik

Xem stackoverflow.com/a/57807913/9843399 để biết câu trả lời liên quan cung cấp cho bạn tên của các tác vụ.
Caleb Syring

10

Nếu bạn đang sử dụng Celery + Django, cách đơn giản nhất để kiểm tra các tác vụ bằng cách sử dụng các lệnh trực tiếp từ thiết bị đầu cuối của bạn trong môi trường ảo hoặc sử dụng đường dẫn đầy đủ đến cần tây:

Tài liệu : 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

Ngoài ra nếu bạn đang sử dụng Celery + RabbitMQ, bạn có thể kiểm tra danh sách hàng đợi bằng lệnh sau:

Thông tin thêm : https://linux.die.net/man/1/rabbitmqctl

$ sudo rabbitmqctl list_queues

4
Nếu bạn có một dự án xác định, bạn có thể sử dụngcelery -A my_proj inspect reserved
sashaboulouds

6

Một giải pháp sao chép-dán cho Redis với tuần tự 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

Nó hoạt động với Django. Chỉ cần đừng quên thay đổi yourproject.celery.


1
Nếu bạn đang sử dụng bộ nối tiếp dưa chua, thì bạn có thể thay đổi body =dòng thành body = pickle.loads(base64.b64decode(j['body'])).
Jim Hunziker

4

Các mô-đun kiểm tra cần tây dường như chỉ nhận thức được các nhiệm vụ từ quan điểm của công nhân. Nếu bạn muốn xem các tin nhắn trong hàng đợi (chưa được nhân viên kéo) tôi khuyên bạn nên sử dụng pyrabbit , có thể giao tiếp với rabbitmq http api để lấy tất cả các loại thông tin từ hàng đợi.

Một ví dụ có thể được tìm thấy ở đây: Lấy chiều dài hàng đợi với Celery (RabbitMQ, Django)


3

Tôi nghĩ cách duy nhất để nhận các nhiệm vụ đang chờ là giữ một danh sách các nhiệm vụ bạn đã bắt đầu và để nhiệm vụ tự xóa khỏi danh sách khi nó bắt đầu.

Với rabbitmqctl và list_queues, bạn có thể có được cái nhìn tổng quan về số lượng nhiệm vụ đang chờ, nhưng không phải là chính các nhiệm vụ: http://www.rabbitmq.com/man/rabbitmqctl.1.man.html

Nếu những gì bạn muốn bao gồm nhiệm vụ đang được xử lý, nhưng chưa kết thúc, bạn có thể giữ một danh sách các nhiệm vụ của bạn và kiểm tra trạng thái của chúng:

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

result.ready() # True if finished

Hoặc bạn để Celery lưu trữ kết quả với CELERY_RESULT_BACKEND và kiểm tra xem nhiệm vụ nào của bạn không có trong đó.


3

Điều này làm việc cho tôi trong ứng dụng của tôi:

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 sẽ là một danh sách các chuỗi tương ứng với các nhiệm vụ trong hàng đợi.

Đừng quên trao đổi CELERY_APP_INSTANCE với chính bạn.

Cảm ơn @ashish đã chỉ cho tôi đi đúng hướng với câu trả lời của anh ấy tại đây: https://stackoverflow.com/a/19465670/9843399


trong trường hợp của tôi jobsluôn luôn bằng không ... có ý kiến ​​gì không?
mã daveon

@daveoncode Tôi không nghĩ rằng đó là đủ thông tin để tôi trả lời một cách hữu ích. Bạn có thể mở câu hỏi của riêng bạn. Tôi không nghĩ nó sẽ là bản sao của cái này nếu bạn xác định rằng bạn muốn lấy thông tin bằng python. Tôi sẽ quay trở lại stackoverflow.com/a/19465670/9843399 , đó là những gì tôi dựa trên câu trả lời của mình và đảm bảo rằng nó hoạt động trước.
Caleb Syring

@CalebSyring Đây là cách tiếp cận đầu tiên thực sự cho tôi thấy các nhiệm vụ được xếp hàng. Rất đẹp. Vấn đề duy nhất đối với tôi là danh sách nối thêm dường như không hoạt động. Bất kỳ ý tưởng làm thế nào tôi có thể làm cho chức năng gọi lại ghi vào danh sách?
Varlor

@Varlor Tôi xin lỗi, ai đó đã chỉnh sửa không đúng với câu trả lời của tôi. Bạn có thể xem trong lịch sử chỉnh sửa cho câu trả lời ban đầu, rất có thể sẽ phù hợp với bạn. Tôi đang làm việc để sửa lỗi này. (EDIT: Tôi vừa mới vào và từ chối chỉnh sửa, có lỗi python rõ ràng. Hãy cho tôi biết nếu điều này khắc phục vấn đề của bạn hay không.)
Caleb Syring

@CalebSyring Bây giờ tôi đã sử dụng mã của bạn trong một lớp, có danh sách là thuộc tính lớp hoạt động!
Varlor

2

Theo như tôi biết thì Celery không cung cấp API để kiểm tra các nhiệm vụ đang chờ trong hàng đợi. Đây là đặc thù môi giới. Nếu bạn sử dụng Redis làm nhà môi giới làm ví dụ, thì việc kiểm tra các tác vụ đang chờ trong celeryhàng đợi (mặc định) cũng đơn giản như:

  1. kết nối với cơ sở dữ liệu môi giới
  2. liệt kê các mục trong celerydanh sách (ví dụ lệnh LRANGE)

Hãy nhớ rằng đây là những nhiệm vụ CHỜ ĐỢI được chọn bởi những nhân viên có sẵn. Cụm của bạn có thể có một số tác vụ đang chạy - những tác vụ đó sẽ không nằm trong danh sách này vì chúng đã được chọn.


1

Tôi đã đi đến kết luận cách tốt nhất để có được số lượng công việc trên hàng đợi là sử dụng rabbitmqctlnhư đã được đề xuất nhiều lần ở đây. Để cho phép bất kỳ người dùng nào được chọn chạy lệnh với sudotôi, tôi đã làm theo các hướng dẫn ở đây (Tôi đã bỏ qua việc chỉnh sửa phần hồ sơ vì tôi không ngại gõ sudo trước lệnh.)

Tôi cũng chộp lấy jamesc grepcutđoạn trích và gói nó trong các cuộc gọi của quy trình con.

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

Nếu bạn kiểm soát mã của các tác vụ thì bạn có thể giải quyết vấn đề bằng cách để một tác vụ kích hoạt thử lại tầm thường trong lần đầu tiên thực thi, sau đó kiểm tra inspect().reserved(). Thử lại đăng ký nhiệm vụ với phụ trợ kết quả và cần tây có thể thấy điều đó. Tác vụ phải chấp nhận selfhoặc contextlà tham số đầu tiên để chúng tôi có thể truy cập vào số lần thử lại.

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

Giải pháp này là bất khả tri môi giới, tức là. bạn không phải lo lắng về việc bạn đang sử dụng RabbitMQ hay Redis để lưu trữ các tác vụ.

EDIT: sau khi thử nghiệm tôi thấy đây chỉ là một giải pháp một phần. Kích thước dành riêng được giới hạn trong cài đặt tìm nạp trước cho công nhân.


0

Với 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))

Hãy cẩn thận để thay đổi my_projvớiyour_proj

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.