Как я могу получить список задач в очереди, которые еще предстоит обработать?
Как я могу получить список задач в очереди, которые еще предстоит обработать?
Ответы:
РЕДАКТИРОВАТЬ: см. Другие ответы для получения списка задач в очереди.
Вы должны посмотреть здесь: Сельдерей Руководство - осмотр рабочих
В основном это:
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
по умолчанию используется is 0
и QUEUE_NAME
is 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']))
.
Модуль проверки сельдерея, кажется, знает только о задачах с точки зрения рабочих. Если вы хотите просмотреть сообщения, находящиеся в очереди (которые еще не были извлечены рабочими), я предлагаю использовать пирабит , который может взаимодействовать с 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
всегда ноль ... есть идеи?
Насколько я знаю, Celery не предоставляет 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 для хранения задач.
РЕДАКТИРОВАТЬ: после тестирования я обнаружил, что это только частичное решение. Размер зарезервированного ограничен настройкой предварительной выборки для работника.
С 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