Як я можу отримати список завдань у черзі, які ще обробляються?
Як я можу отримати список завдань у черзі, які ще обробляються?
Відповіді:
РЕДАКТУВАННЯ: Див. Інші відповіді для отримання списку завдань у черзі.
Ви повинні подивитися тут: Посібник із селери - Огляд робітників
В основному це:
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()
Залежно від того, що ви хочете
i.reserved()
для отримання списку завдань у черзі.
inspect(['celery@Flatty'])
. Величезне покращення швидкості з часом inspect()
.
якщо ви використовуєте 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 очікуючих завдань.
grep -e "^celery\s" | cut -f2
передати це, щоб витягти, що, 166
якщо ви хочете обробити це число пізніше, скажімо, для статистики.
Якщо ви не використовуєте пріоритетні завдання, це насправді досить просто, якщо ви використовуєте 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']))
Зауважте, що дезаріалізація може зайняти мить, і вам потрібно буде скоригувати команди вище, щоб працювати з різними пріоритетами.
DATABASE_NUMBER
за замовчуванням використовується те, що є 0
, і QUEUE_NAME
є celery
, тому redis-cli -n 0 llen celery
поверне кількість повідомлень у черзі.
'{{{0}}}{1}{2}'
замість цього , назва черги '{0}{1}{2}'
. Крім цього, це прекрасно працює!
Щоб отримати завдання із бекенда, використовуйте це
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)
Якщо ви використовуєте Celery + Django, найпростіший спосіб перевірити завдання, використовуючи команди безпосередньо з вашого терміналу у вашому віртуальному середовищі або використовуючи повний шлях до селери:
Документ : 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
celery -A my_proj inspect reserved
Рішення для копіювання та вставки для 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
Це працює з Джанго. Просто не забудьте змінити yourproject.celery
.
body =
рядок на body = pickle.loads(base64.b64decode(j['body']))
.
Можливо, модуль огляду селери знає про завдання лише з точки зору працівників. Якщо ви хочете переглянути повідомлення, які перебувають у черзі (ще їх не витягнуть робітники), я пропоную використовувати pyrabbit , який може взаємодіяти з rabbitmq http api для отримання всіх видів інформації з черги.
Приклад можна знайти тут: Отримайте довжину черги за допомогою селери (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 і перевіряти, які з ваших завдань там немає.
Це працювало для мене в моїй заявці:
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
завжди нуль ... будь-яка ідея?
Наскільки мені відомо, селера не дає API для вивчення завдань, які чекають у черзі. Це специфічно для брокера. Якщо ви використовуєте Redis в якості брокера для прикладу, розгляд завдань, які чекають у celery
черзі (за замовчуванням), такий же простий, як:
celery
списку (команда LRANGE для прикладу)Майте на увазі, що це ЗАЧЕКУВАННЯ, які повинні обрати наявні працівники. У вашому кластері можуть бути запущені деякі завдання - їх не буде в цьому списку, як вони вже були вибрані.
Я прийшов до висновку, що найкращий спосіб отримати кількість завдань на черзі - це використовувати, rabbitmqctl
як було запропоновано тут кілька разів. Щоб дозволити будь-якому обраному користувачеві виконувати команду, sudo
я дотримувався інструкцій тут (я пропустив редагування частини профілю, оскільки не проти вводити sudo перед командою.)
Я також схопив jamesc's grep
і cut
фрагмент і загорнув його в підпроцесові дзвінки.
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()
. Повторне завдання реєструє завдання з результатом пошуку, і селера може це бачити. Завдання має приймати self
або context
як перший параметр, щоб ми могли отримати доступ до кількості повторних спроб.
@task(bind=True)
def mytask(self):
if self.request.retries == 0:
raise self.retry(exc=MyTrivialError(), countdown=1)
...
Це рішення є брокерським агностиком, тобто. вам не потрібно турбуватися про те, чи використовуєте Ви RabbitMQ або Redis для зберігання завдань.
EDIT: після тестування я вважав, що це лише часткове рішення. Розмір зарезервованого обмежений налаштуванням попереднього вибору для працівника.
З 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