Ambil daftar tugas dalam antrian di Seledri

147

Bagaimana saya bisa mengambil daftar tugas dalam antrian yang belum diproses?

bradley.ayers
sumber
1
RabbitMQ, tapi saya ingin mengambil daftar ini di dalam Python.
bradley.ayers

Jawaban:

174

Sunting: Lihat jawaban lain untuk mendapatkan daftar tugas dalam antrian.

Anda harus melihat di sini: Panduan Seledri - Memeriksa Pekerja

Pada dasarnya ini:

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

Tergantung apa yang kamu inginkan

semarj
sumber
9
Saya mencoba itu, tapi itu benar-benar lambat (seperti 1 detik). Saya menggunakannya secara serempak dalam aplikasi tornado untuk memantau kemajuan, jadi itu harus cepat.
JulienFr
41
Ini tidak akan mengembalikan daftar tugas dalam antrian yang belum diproses.
Ed J
9
Gunakan i.reserved()untuk mendapatkan daftar tugas yang antri.
Pisang
4
Adakah yang pernah mengalami bahwa saya.reserved () tidak akan memiliki daftar tugas aktif yang akurat? Saya memiliki tugas yang berjalan yang tidak muncul dalam daftar. Saya sedang di django-
selery
6
Ketika menentukan pekerja saya harus menggunakan daftar sebagai argumen: inspect(['celery@Flatty']). Peningkatan kecepatan besar berakhir inspect().
Adversus
42

jika Anda menggunakan rabbitMQ, gunakan ini di terminal:

sudo rabbitmqctl list_queues

itu akan mencetak daftar antrian dengan jumlah tugas yang tertunda. sebagai contoh:

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

angka di kolom kanan adalah jumlah tugas dalam antrian. di atas, antrian seledri memiliki 166 tugas yang tertunda.

Ali
sumber
1
Saya mengetahui hal ini ketika saya memiliki hak sudo, tetapi saya ingin pengguna sistem yang tidak terjangkau dapat memeriksa - saran?
bijak
Selain itu, Anda dapat mengirimkan melalui ini grep -e "^celery\s" | cut -f2untuk mengekstrak bahwa 166jika Anda ingin memproses angka itu nanti, katakan untuk statistik.
jamesc
22

Jika Anda tidak menggunakan tugas yang diprioritaskan, ini sebenarnya cukup sederhana jika Anda menggunakan Redis. Untuk mendapatkan jumlah tugas:

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

Tapi, tugas yang diprioritaskan menggunakan kunci yang berbeda dalam redis , sehingga gambaran lengkapnya sedikit lebih rumit. Gambaran lengkapnya adalah Anda harus meminta redis untuk setiap prioritas tugas. Dalam python (dan dari proyek Bunga), ini terlihat seperti:

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

Jika Anda ingin mendapatkan tugas yang sebenarnya, Anda dapat menggunakan sesuatu seperti:

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

Dari sana Anda harus membatalkan daftar yang dikembalikan. Dalam kasus saya, saya dapat mencapai ini dengan sesuatu seperti:

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

Harap diingat bahwa deserialisasi dapat berlangsung sesaat, dan Anda harus menyesuaikan perintah di atas untuk bekerja dengan berbagai prioritas.

mlissner
sumber
Setelah menggunakan ini dalam produksi, saya telah belajar bahwa itu gagal jika Anda menggunakan tugas yang diprioritaskan , karena desain Seledri.
mlissner
1
Saya telah memperbarui hal di atas untuk menangani tugas-tugas yang diprioritaskan. Kemajuan!
mlissner
1
Hanya untuk menguraikan hal-hal, yang DATABASE_NUMBERdigunakan secara default adalah 0, dan apa QUEUE_NAMEadanya celery, sehingga redis-cli -n 0 llen celeryakan mengembalikan jumlah pesan yang antri.
Vineet Bansal
Untuk seledri saya, nama antriannya '{{{0}}}{1}{2}'bukan '{0}{1}{2}'. Selain itu, ini bekerja dengan sempurna!
zupo
12

Untuk mengambil tugas dari backend, gunakan ini

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)
abu
sumber
2
tetapi 'pekerjaan' hanya memberikan jumlah tugas dalam antrian
bitnik
Lihat stackoverflow.com/a/57807913/9843399 untuk jawaban terkait yang memberi Anda nama tugas.
Caleb Syring
10

Jika Anda menggunakan Seledri + Django cara paling sederhana untuk memeriksa tugas menggunakan perintah langsung dari terminal Anda di lingkungan virtual Anda atau menggunakan path lengkap ke seledri:

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

Juga jika Anda menggunakan Celery + RabbitMQ Anda dapat memeriksa daftar antrian menggunakan perintah berikut:

Info lebih lanjut : https://linux.die.net/man/1/rabbitmqctl

$ sudo rabbitmqctl list_queues
Alexandr S.
sumber
4
Jika Anda memiliki proyek define, Anda dapat menggunakancelery -A my_proj inspect reserved
sashaboulouds
6

Solusi salin-tempel untuk Redis dengan serialisasi 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

Ini bekerja dengan Django. Hanya saja, jangan lupa untuk berubah yourproject.celery.

Max Malysh
sumber
1
Jika Anda menggunakan serializer acar, maka Anda dapat mengubah body =jalurnya menjadi body = pickle.loads(base64.b64decode(j['body'])).
Jim Hunziker
4

Modul pemeriksaan seledri tampaknya hanya menyadari tugas-tugas dari perspektif pekerja. Jika Anda ingin melihat pesan-pesan yang ada dalam antrian (belum ditarik oleh para pekerja) Saya sarankan untuk menggunakan pyrabbit , yang dapat berinteraksi dengan rabbitmq http api untuk mengambil semua jenis informasi dari antrian.

Contoh dapat ditemukan di sini: Ambil panjang antrian dengan Seledri (RabbitMQ, Django)

Paul di Hout
sumber
3

Saya pikir satu-satunya cara untuk mendapatkan tugas-tugas yang sedang menunggu adalah menyimpan daftar tugas yang Anda mulai dan membiarkan tugas menghapus dirinya sendiri dari daftar ketika sudah dimulai.

Dengan rabbitmqctl dan list_queues Anda bisa mendapatkan gambaran umum tentang berapa banyak tugas yang menunggu, tetapi bukan tugas itu sendiri: http://www.rabbitmq.com/man/rabbitmqctl.1.man.html

Jika yang Anda inginkan termasuk tugas yang sedang diproses, tetapi belum selesai, Anda dapat menyimpan daftar tugas Anda dan memeriksa statusnya:

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

result.ready() # True if finished

Atau Anda membiarkan Celery menyimpan hasilnya dengan CELERY_RESULT_BACKEND dan memeriksa tugas Anda yang tidak ada di sana.

Sebastian Blask
sumber
3

Ini berfungsi untuk saya dalam aplikasi saya:

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 akan menjadi daftar string yang sesuai dengan tugas dalam antrian.

Jangan lupa untuk menukar CELERY_APP_INSTANCE dengan milik Anda.

Terima kasih kepada @ashish karena mengarahkan saya ke arah yang benar dengan jawabannya di sini: https://stackoverflow.com/a/19465670/9843399

Caleb Syring
sumber
dalam kasus saya jobsselalu nol ... ada ide?
daveoncode
@donconcode Saya tidak berpikir itu informasi yang cukup bagi saya untuk merespon dengan membantu. Anda bisa membuka pertanyaan Anda sendiri. Saya tidak berpikir itu akan menjadi duplikat yang satu ini jika Anda menentukan bahwa Anda ingin mengambil informasi dengan python. Saya akan kembali ke stackoverflow.com/a/19465670/9843399 , yang merupakan dasar dari jawaban saya, dan pastikan itu berfungsi lebih dulu.
Caleb Syring
@ CalebSyring Ini adalah pendekatan pertama yang benar-benar menunjukkan kepada saya tugas yang antri. Sangat bagus. Satu-satunya masalah bagi saya adalah bahwa daftar tambahan tampaknya tidak berfungsi. Adakah ide bagaimana saya dapat membuat fungsi callback menulis ke daftar?
Varlor
@ Varlor Maaf, ada orang yang mengedit jawaban saya dengan tidak tepat. Anda dapat melihat pada riwayat edit untuk jawaban asli, yang kemungkinan besar akan berhasil untuk Anda. Saya sedang berusaha memperbaiki ini. (EDIT: Saya baru saja masuk dan menolak hasil edit, yang memiliki kesalahan python yang jelas. Beri tahu saya apakah ini memperbaiki masalah Anda atau tidak.)
Caleb Syring
@ CalebSyring Saya sekarang menggunakan kode Anda di kelas, memiliki daftar sebagai atribut kelas berfungsi!
Varlor
2

Sejauh yang saya tahu, Selery tidak memberikan API untuk memeriksa tugas-tugas yang menunggu dalam antrian. Ini khusus broker. Jika Anda menggunakan Redis sebagai broker sebagai contoh, maka memeriksa tugas yang menunggu dalam celeryantrian (default) semudah:

  1. terhubung ke database broker
  2. daftar item dalam celerydaftar (perintah LRANGE misalnya)

Perlu diingat bahwa ini adalah tugas yang menunggu untuk dipilih oleh pekerja yang tersedia. Cluster Anda mungkin memiliki beberapa tugas berjalan - itu tidak akan ada dalam daftar ini karena mereka sudah dipilih.

DejanLekic
sumber
1

Saya sampai pada kesimpulan cara terbaik untuk mendapatkan jumlah pekerjaan dalam antrian adalah dengan menggunakan rabbitmqctlseperti yang disarankan beberapa kali di sini. Untuk mengizinkan pengguna yang dipilih untuk menjalankan perintah dengan sudosaya mengikuti instruksi di sini (saya melewatkan mengedit bagian profil karena saya tidak keberatan mengetikkan sudo sebelum perintah.)

Saya juga mengambil jamesc grepdan cutsnippet dan membungkusnya dalam panggilan subproses.

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]))
Peter Shannon
sumber
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
张朝龙
sumber
0

Jika Anda mengontrol kode tugas maka Anda dapat mengatasi masalah dengan membiarkan tugas memicu percobaan ulang yang sepele saat pertama kali dijalankan, lalu memeriksa inspect().reserved(). Coba lagi mendaftarkan tugas dengan backend hasil, dan seledri dapat melihatnya. Tugas harus menerima selfatau contextsebagai parameter pertama agar kami dapat mengakses jumlah coba lagi.

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

Solusi ini adalah broker agnostik, yaitu. Anda tidak perlu khawatir tentang apakah Anda menggunakan RabbitMQ atau Redis untuk menyimpan tugas.

EDIT: setelah pengujian saya menemukan ini hanya solusi parsial. Ukuran yang dipesan terbatas pada pengaturan prefetch untuk pekerja.

hedleyroos
sumber
0

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

Hati-hati untuk mengubah my_projdenganyour_proj

sashaboulouds
sumber