ดึงรายการของงานในคิวในผักชีฝรั่ง


147

ฉันจะดึงรายการของงานในคิวที่ยังไม่ได้ดำเนินการได้อย่างไร


1
RabbitMQ แต่ฉันต้องการดึงรายการนี้มาจาก Python
bradley.ayers

คำตอบ:


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

41
นี่จะไม่ส่งคืนรายการงานในคิวที่ยังไม่ได้ดำเนินการ
Ed J

9
ใช้i.reserved()เพื่อรับรายการงานที่อยู่ในคิว
Banana

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

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

เพิ่งได้รับการเตือนว่าการดีซีเรียลไลเซชั่นอาจใช้เวลาสักครู่และคุณจะต้องปรับคำสั่งด้านบนเพื่อทำงานกับลำดับความสำคัญต่าง ๆ


หลังจากใช้สิ่งนี้ในการผลิตฉันได้เรียนรู้ว่ามันล้มเหลวหากคุณใช้งานที่มีความสำคัญเนื่องจากการออกแบบของขึ้นฉ่าย
mlissner

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
แต่ 'jobs' ให้จำนวนงานในคิวเท่านั้น
bitnik

ดูstackoverflow.com/a/57807913/9843399สำหรับคำตอบที่เกี่ยวข้องที่ให้ชื่อของงานคุณ
Caleb Syring

10

หากคุณกำลังใช้Celery + Djangoวิธีที่ง่ายที่สุดในการตรวจสอบงานโดยใช้คำสั่งโดยตรงจากเทอร์มินัลของคุณในสภาพแวดล้อมเสมือนจริงของคุณหรือใช้เส้นทางเต็มไปยังผักชีฝรั่ง:

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

โซลูชันการคัดลอกวางสำหรับ Redis พร้อมการจัดลำดับ 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

มันทำงานร่วมกับ Django yourproject.celeryก็ไม่ลืมที่จะเปลี่ยน


1
หากคุณกำลังใช้เครื่องซีเรียลไลเซอร์อนุกรมแล้วคุณสามารถเปลี่ยนbody =สายเป็น body = pickle.loads(base64.b64decode(j['body']))
Jim Hunziker

4

โมดูลตรวจสอบคื่นฉ่ายดูเหมือนจะรับรู้เฉพาะงานจากมุมมองของผู้ปฏิบัติงาน หากคุณต้องการดูข้อความที่อยู่ในคิว (ยังไม่ได้ถูกดึงโดยคนงาน) ฉันแนะนำให้ใช้pyrabbitซึ่งสามารถเชื่อมต่อกับ Rabbitmq http api เพื่อดึงข้อมูลทุกชนิดจากคิว

ตัวอย่างสามารถพบได้ที่นี่: ดึงความยาวคิวด้วย Celery (RabbitMQ, Django)


3

ฉันคิดว่าวิธีเดียวที่จะได้งานที่รอคือการเก็บรายการงานที่คุณเริ่มและปล่อยให้งานลบตัวเองออกจากรายการเมื่อเริ่มทำงาน

ด้วย 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 และตรวจสอบว่างานใดที่คุณไม่ได้เข้าร่วม


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 ฉันไม่คิดว่าเป็นข้อมูลที่เพียงพอสำหรับฉันที่จะตอบสนองอย่างเป็นประโยชน์ คุณสามารถเปิดคำถามของคุณเอง ฉันไม่คิดว่ามันจะซ้ำกับของอันนี้ถ้าคุณระบุว่าคุณต้องการดึงข้อมูลในไพ ธ อน ฉันจะกลับไปที่stackoverflow.com/a/19465670/9843399ซึ่งเป็นสิ่งที่ฉันทำตามคำตอบของฉันและตรวจสอบให้แน่ใจว่ามันใช้ได้ก่อน
Caleb Syring

@CalebSyring นี่เป็นวิธีแรกที่แสดงให้ฉันเห็นถึงงานที่ถูกจัดคิว ดีมาก. ปัญหาเดียวสำหรับฉันคือรายการต่อท้ายดูเหมือนจะไม่ทำงาน ความคิดใดที่ฉันจะทำให้ฟังก์ชั่นโทรกลับเขียนลงในรายการ
Varlor

@Vlorlor ฉันขอโทษมีคนแก้ไขคำตอบของฉันไม่เหมาะสม คุณสามารถดูประวัติการแก้ไขสำหรับคำตอบดั้งเดิมซึ่งน่าจะเหมาะกับคุณที่สุด ฉันกำลังแก้ไขปัญหานี้อยู่ (แก้ไข: ฉันเพิ่งเข้าไปข้างในและปฏิเสธการแก้ไขซึ่งมีข้อผิดพลาด python ชัดเจนแจ้งให้เราทราบว่าสิ่งนี้แก้ไขปัญหาของคุณได้หรือไม่)
Caleb Syring

@CalebSyring ตอนนี้ฉันใช้รหัสของคุณในชั้นเรียนโดยมีรายการเป็นแอตทริบิวต์ class ใช้งานได้!
Varlor

2

เท่าที่ฉันรู้ Celery ไม่ได้ให้ API สำหรับการตรวจสอบงานที่รออยู่ในคิว นี่คือเฉพาะนายหน้า หากคุณใช้ Redis เป็นนายหน้าสำหรับตัวอย่างการตรวจสอบงานที่รออยู่ในceleryคิว (ค่าเริ่มต้น) นั้นง่ายเหมือน:

  1. เชื่อมต่อกับฐานข้อมูลนายหน้า
  2. รายการในceleryรายการ (คำสั่ง LRANGE สำหรับตัวอย่าง)

พึงระลึกไว้เสมอว่าสิ่งเหล่านี้เป็นภาระหน้าที่รอคอยที่จะถูกเลือกโดยพนักงานที่มีอยู่ คลัสเตอร์ของคุณอาจมีงานบางอย่างทำงาน - งานเหล่านั้นจะไม่อยู่ในรายการนี้เนื่องจากถูกเลือกแล้ว


1

ฉันได้ข้อสรุปวิธีที่ดีที่สุดในการรับจำนวนงานในคิวคือการใช้rabbitmqctlตามที่ได้รับการแนะนำหลายครั้งที่นี่ เพื่อให้ผู้ใช้ที่เลือกรันคำสั่งด้วยsudoฉันทำตามคำแนะนำที่นี่ (ฉันข้ามการแก้ไขส่วนโปรไฟล์เนื่องจากฉันไม่รังเกียจที่จะพิมพ์ใน sudo ก่อนคำสั่ง)

ฉันยังจับ jamesc's grepและcutsnippet และห่อมันด้วยการเรียก subprocess

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 เพื่อจัดเก็บงาน

แก้ไข: หลังจากการทดสอบฉันพบว่านี่เป็นเพียงการแก้ปัญหาบางส่วน ขนาดของสงวนถูก จำกัด ไว้ที่การตั้งค่าการดึงข้อมูลล่วงหน้าสำหรับผู้ปฏิบัติงาน


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.