Bagaimana saya bisa mengambil daftar tugas dalam antrian yang belum diproses?
Bagaimana saya bisa mengambil daftar tugas dalam antrian yang belum diproses?
Jawaban:
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
i.reserved()
untuk mendapatkan daftar tugas yang antri.
inspect(['celery@Flatty'])
. Peningkatan kecepatan besar berakhir inspect()
.
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.
grep -e "^celery\s" | cut -f2
untuk mengekstrak bahwa 166
jika Anda ingin memproses angka itu nanti, katakan untuk statistik.
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.
DATABASE_NUMBER
digunakan secara default adalah 0
, dan apa QUEUE_NAME
adanya celery
, sehingga redis-cli -n 0 llen celery
akan mengembalikan jumlah pesan yang antri.
'{{{0}}}{1}{2}'
bukan '{0}{1}{2}'
. Selain itu, ini bekerja dengan sempurna!
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)
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
celery -A my_proj inspect reserved
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
.
body =
jalurnya menjadi body = pickle.loads(base64.b64decode(j['body']))
.
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)
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.
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
jobs
selalu nol ... ada ide?
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 celery
antrian (default) semudah:
celery
daftar (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.
Saya sampai pada kesimpulan cara terbaik untuk mendapatkan jumlah pekerjaan dalam antrian adalah dengan menggunakan rabbitmqctl
seperti yang disarankan beberapa kali di sini. Untuk mengizinkan pengguna yang dipilih untuk menjalankan perintah dengan sudo
saya mengikuti instruksi di sini (saya melewatkan mengedit bagian profil karena saya tidak keberatan mengetikkan sudo sebelum perintah.)
Saya juga mengambil jamesc grep
dan cut
snippet 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]))
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 self
atau context
sebagai 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.
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_proj
denganyour_proj