Làm cách nào tôi có thể truy xuất danh sách các tác vụ trong hàng đợi chưa được xử lý?
Làm cách nào tôi có thể truy xuất danh sách các tác vụ trong hàng đợi chưa được xử lý?
Câu trả lời:
EDIT: Xem các câu trả lời khác để nhận danh sách các nhiệm vụ trong hàng đợi.
Bạn nên xem tại đây: Hướng dẫn cần tây - Kiểm tra công nhân
Về cơ bản này:
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()
Tùy thuộc vào những gì bạn muốn
i.reserved()
để có được một danh sách các nhiệm vụ xếp hàng.
inspect(['celery@Flatty'])
. Cải thiện tốc độ rất lớn inspect()
.
nếu bạn đang sử dụng rabbitMQ, hãy sử dụng cái này trong terminal:
sudo rabbitmqctl list_queues
nó sẽ in danh sách các hàng đợi với số lượng tác vụ đang chờ xử lý. ví dụ:
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
số ở cột bên phải là số nhiệm vụ trong hàng đợi. ở trên, hàng đợi cần tây có 166 nhiệm vụ đang chờ xử lý.
grep -e "^celery\s" | cut -f2
để trích xuất rằng 166
nếu bạn muốn xử lý số đó sau, hãy nói về số liệu thống kê.
Nếu bạn không sử dụng các nhiệm vụ ưu tiên, điều này thực sự khá đơn giản nếu bạn đang sử dụng Redis. Để có được nhiệm vụ:
redis-cli -h HOST -p PORT -n DATABASE_NUMBER llen QUEUE_NAME
Nhưng, các tác vụ ưu tiên sử dụng một khóa khác trong redis , vì vậy bức tranh đầy đủ phức tạp hơn một chút. Hình ảnh đầy đủ là bạn cần truy vấn redis cho mọi ưu tiên của nhiệm vụ. Trong python (và từ dự án Hoa), nó trông giống như:
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])
Nếu bạn muốn nhận một nhiệm vụ thực tế, bạn có thể sử dụng một cái gì đó như:
redis-cli -h HOST -p PORT -n DATABASE_NUMBER lrange QUEUE_NAME 0 -1
Từ đó bạn sẽ phải giải tuần tự hóa danh sách trả về. Trong trường hợp của tôi, tôi đã có thể thực hiện điều này với một cái gì đó như:
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']))
Chỉ cần cảnh báo rằng khử lưu huỳnh có thể mất một chút thời gian và bạn sẽ cần điều chỉnh các lệnh trên để làm việc với các ưu tiên khác nhau.
DATABASE_NUMBER
sử dụng bởi mặc định là 0
, và QUEUE_NAME
là celery
, do đó redis-cli -n 0 llen celery
sẽ trả lại số tin nhắn xếp hàng đợi.
'{{{0}}}{1}{2}'
thay vì '{0}{1}{2}'
. Ngoài ra, điều này hoạt động hoàn hảo!
Để lấy các tác vụ từ phụ trợ, hãy sử dụng
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)
Nếu bạn đang sử dụng Celery + Django, cách đơn giản nhất để kiểm tra các tác vụ bằng cách sử dụng các lệnh trực tiếp từ thiết bị đầu cuối của bạn trong môi trường ảo hoặc sử dụng đường dẫn đầy đủ đến cần tây:
Tài liệu : 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
Ngoài ra nếu bạn đang sử dụng Celery + RabbitMQ, bạn có thể kiểm tra danh sách hàng đợi bằng lệnh sau:
Thông tin thêm : https://linux.die.net/man/1/rabbitmqctl
$ sudo rabbitmqctl list_queues
celery -A my_proj inspect reserved
Một giải pháp sao chép-dán cho Redis với tuần tự 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
Nó hoạt động với Django. Chỉ cần đừng quên thay đổi yourproject.celery
.
body =
dòng thành body = pickle.loads(base64.b64decode(j['body']))
.
Các mô-đun kiểm tra cần tây dường như chỉ nhận thức được các nhiệm vụ từ quan điểm của công nhân. Nếu bạn muốn xem các tin nhắn trong hàng đợi (chưa được nhân viên kéo) tôi khuyên bạn nên sử dụng pyrabbit , có thể giao tiếp với rabbitmq http api để lấy tất cả các loại thông tin từ hàng đợi.
Một ví dụ có thể được tìm thấy ở đây: Lấy chiều dài hàng đợi với Celery (RabbitMQ, Django)
Tôi nghĩ cách duy nhất để nhận các nhiệm vụ đang chờ là giữ một danh sách các nhiệm vụ bạn đã bắt đầu và để nhiệm vụ tự xóa khỏi danh sách khi nó bắt đầu.
Với rabbitmqctl và list_queues, bạn có thể có được cái nhìn tổng quan về số lượng nhiệm vụ đang chờ, nhưng không phải là chính các nhiệm vụ: http://www.rabbitmq.com/man/rabbitmqctl.1.man.html
Nếu những gì bạn muốn bao gồm nhiệm vụ đang được xử lý, nhưng chưa kết thúc, bạn có thể giữ một danh sách các nhiệm vụ của bạn và kiểm tra trạng thái của chúng:
from tasks import add
result = add.delay(4, 4)
result.ready() # True if finished
Hoặc bạn để Celery lưu trữ kết quả với CELERY_RESULT_BACKEND và kiểm tra xem nhiệm vụ nào của bạn không có trong đó.
Điều này làm việc cho tôi trong ứng dụng của tôi:
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
sẽ là một danh sách các chuỗi tương ứng với các nhiệm vụ trong hàng đợi.
Đừng quên trao đổi CELERY_APP_INSTANCE với chính bạn.
Cảm ơn @ashish đã chỉ cho tôi đi đúng hướng với câu trả lời của anh ấy tại đây: https://stackoverflow.com/a/19465670/9843399
jobs
luôn luôn bằng không ... có ý kiến gì không?
Theo như tôi biết thì Celery không cung cấp API để kiểm tra các nhiệm vụ đang chờ trong hàng đợi. Đây là đặc thù môi giới. Nếu bạn sử dụng Redis làm nhà môi giới làm ví dụ, thì việc kiểm tra các tác vụ đang chờ trong celery
hàng đợi (mặc định) cũng đơn giản như:
celery
danh sách (ví dụ lệnh LRANGE)Hãy nhớ rằng đây là những nhiệm vụ CHỜ ĐỢI được chọn bởi những nhân viên có sẵn. Cụm của bạn có thể có một số tác vụ đang chạy - những tác vụ đó sẽ không nằm trong danh sách này vì chúng đã được chọn.
Tôi đã đi đến kết luận cách tốt nhất để có được số lượng công việc trên hàng đợi là sử dụng rabbitmqctl
như đã được đề xuất nhiều lần ở đây. Để cho phép bất kỳ người dùng nào được chọn chạy lệnh với sudo
tôi, tôi đã làm theo các hướng dẫn ở đây (Tôi đã bỏ qua việc chỉnh sửa phần hồ sơ vì tôi không ngại gõ sudo trước lệnh.)
Tôi cũng chộp lấy jamesc grep
và cut
đoạn trích và gói nó trong các cuộc gọi của quy trình con.
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]))
Nếu bạn kiểm soát mã của các tác vụ thì bạn có thể giải quyết vấn đề bằng cách để một tác vụ kích hoạt thử lại tầm thường trong lần đầu tiên thực thi, sau đó kiểm tra inspect().reserved()
. Thử lại đăng ký nhiệm vụ với phụ trợ kết quả và cần tây có thể thấy điều đó. Tác vụ phải chấp nhận self
hoặc context
là tham số đầu tiên để chúng tôi có thể truy cập vào số lần thử lại.
@task(bind=True)
def mytask(self):
if self.request.retries == 0:
raise self.retry(exc=MyTrivialError(), countdown=1)
...
Giải pháp này là bất khả tri môi giới, tức là. bạn không phải lo lắng về việc bạn đang sử dụng RabbitMQ hay Redis để lưu trữ các tác vụ.
EDIT: sau khi thử nghiệm tôi thấy đây chỉ là một giải pháp một phần. Kích thước dành riêng được giới hạn trong cài đặt tìm nạp trước cho công nhân.
Với 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))
Hãy cẩn thận để thay đổi my_proj
vớiyour_proj