Làm thế nào để kiểm tra trạng thái nhiệm vụ trong Celery?


92

Làm cách nào để kiểm tra xem một tác vụ có đang chạy trong cần tây hay không (cụ thể là tôi đang sử dụng celery-django)?

Tôi đã đọc tài liệu và tôi đã truy cập vào Google, nhưng tôi không thể thấy một cuộc gọi như:

my_example_task.state() == RUNNING

Trường hợp sử dụng của tôi là tôi có một dịch vụ bên ngoài (java) để chuyển mã. Khi tôi gửi một tài liệu cần chuyển mã, tôi muốn kiểm tra xem tác vụ chạy dịch vụ đó có đang chạy hay không và nếu không, hãy (lại) khởi động nó.

Tôi tin rằng tôi đang sử dụng các phiên bản ổn định hiện tại - 2.4.

Câu trả lời:


97

Trả lại task_id (được cung cấp từ .delay ()) và hỏi phiên bản celery sau đó về trạng thái:

x = method.delay(1,2)
print x.task_id

Khi yêu cầu, hãy nhận AsyncResult mới bằng cách sử dụng task_id này:

from celery.result import AsyncResult
res = AsyncResult("your-task-id")
res.ready()

10
Cảm ơn, nhưng nếu tôi không có quyền truy cập xthì sao?
Marcin

4
Bạn sắp xếp công việc của mình vào cần tây ở đâu? Ở đó, bạn phải trả lại task_id để theo dõi công việc trong tương lai.
Gregor

Không giống như @ Marcin's, câu trả lời này không sử dụng phương thức tĩnh Task.AsyncResult () làm nhà máy của AsyncResult, sử dụng lại cấu hình phụ trợ một cách hữu ích, nếu không sẽ xảy ra lỗi khi cố gắng lấy kết quả.
ArnauOrriols,

2
@Chris Cuộc tranh cãi với mã @gregor đang diễn ra async_result. Trong trường hợp sử dụng của bạn, bạn đã có ví dụ, bạn có thể sử dụng. Nhưng điều gì sẽ xảy ra nếu bạn chỉ có id tác vụ và cần khởi tạo một async_resultthể hiện để có thể gọi async_result.get()? Đây là một thể hiện của AsyncResultlớp, nhưng bạn không thể sử dụng lớp thô celery.result.AsyncResult, bạn cần lấy lớp từ hàm được bao bọc bởi app.task(). Trong trường hợp của bạn, bạn sẽ làmasync_result = run_instance.AsyncResult('task-id')
ArnauOrriols 14/02/16

1
but you cannot use the raw class celery.result.AsyncResult, you need to get the class from the function wrapped by app.task(). - Tôi nghĩ đây là cách nó thực sự được sử dụng. Hãy đọc mã: github.com/celery/celery/blob/…
nevelis

70

Tạo một AsyncResultđối tượng từ id nhiệm vụ cách được đề xuất trong Câu hỏi thường gặp để có được trạng thái nhiệm vụ khi thứ duy nhất bạn có là id nhiệm vụ.

Tuy nhiên, đối với Celery 3.x, có những lưu ý đáng kể là có thể cắn người nếu họ không chú ý đến chúng. Nó thực sự phụ thuộc vào từng trường hợp sử dụng cụ thể.

Theo mặc định, Celery không ghi lại trạng thái "đang chạy".

Để Celery ghi lại rằng một tác vụ đang chạy, bạn phải đặt task_track_startedthành True. Đây là một nhiệm vụ đơn giản kiểm tra điều này:

@app.task(bind=True)
def test(self):
    print self.AsyncResult(self.request.id).state

Khi task_track_startedFalse, đó là mặc định, chương trình nhà nước là PENDINGmặc dù nhiệm vụ đã bắt đầu. Nếu bạn đặt task_track_startedthành True, thì trạng thái sẽ là STARTED.

Trạng thái PENDINGcó nghĩa là "Tôi không biết."

An AsyncResultvới bang PENDINGkhông có ý nghĩa gì hơn là Celery không biết tình trạng của nhiệm vụ. Điều này có thể là do bất kỳ lý do nào.

Đối với một điều, AsyncResultcó thể được xây dựng với id nhiệm vụ không hợp lệ. Những "nhiệm vụ" như vậy sẽ được Celery coi là đang chờ xử lý:

>>> task.AsyncResult("invalid").status
'PENDING'

Ok, vì vậy không ai sẽ cung cấp các id rõ ràng không hợp lệ cho AsyncResult. Công bằng, nhưng nó cũng có hiệu lực mà AsyncResultcũng sẽ coi một nhiệm vụ đã chạy thành công nhưng Celery đó đã quên như hiện tại PENDING. Một lần nữa, trong một số trường hợp sử dụng, điều này có thể là một vấn đề. Một phần của vấn đề xoay quanh cách Celery được cấu hình để giữ kết quả của các nhiệm vụ, vì nó phụ thuộc vào tính khả dụng của "bia mộ" trong phần phụ trợ kết quả. ("Tombstone" là thuật ngữ sử dụng trong tài liệu Celery cho các phần dữ liệu ghi lại cách nhiệm vụ đã kết thúc.) Việc sử dụng AsyncResultsẽ không hoạt động nếu task_ignore_resultTrue. Một vấn đề khó chịu hơn là Celery sẽ hết hạn sử dụng bia mộ theo mặc định. Cácresult_expirescài đặt theo mặc định được đặt thành 24 giờ. Vì vậy, nếu bạn khởi chạy một tác vụ và ghi lại id trong bộ nhớ lâu dài và hơn 24 giờ sau, bạn tạo một tác vụ AsyncResultvới nó, trạng thái sẽ là PENDING.

Tất cả các "nhiệm vụ thực" bắt đầu ở PENDINGtrạng thái. Vì vậy, nhận PENDINGmột nhiệm vụ có thể có nghĩa là nhiệm vụ đã được yêu cầu nhưng không bao giờ tiến triển hơn mức này (vì bất kỳ lý do gì). Hoặc nó có thể có nghĩa là nhiệm vụ đã chạy nhưng Celery quên trạng thái của nó.

Ôi chao! AsyncResultsẽ không hiệu quả với tôi. Tôi có thể làm gì nữa?

Tôi thích theo dõi các mục tiêu hơn là theo dõi các nhiệm vụ . Tôi giữ một số thông tin nhiệm vụ nhưng nó thực sự là thứ yếu để theo dõi các mục tiêu. Các mục tiêu được lưu trữ trong bộ lưu trữ độc lập với Celery. Khi một yêu cầu cần thực hiện tính toán phụ thuộc vào một số mục tiêu đã đạt được, nó sẽ kiểm tra xem mục tiêu đã đạt được chưa, nếu có, thì nó sẽ sử dụng mục tiêu được lưu trong bộ nhớ cache này, nếu không, nó sẽ bắt đầu tác vụ sẽ thực hiện mục tiêu và gửi đến máy khách đã thực hiện yêu cầu HTTP một phản hồi cho biết nó sẽ đợi kết quả.


Các tên biến và siêu liên kết ở trên dành cho Celery 4.x. Trong 3.x các biến tương ứng và siêu liên kết là: CELERY_TRACK_STARTED, CELERY_IGNORE_RESULT, CELERY_TASK_RESULT_EXPIRES.


Vì vậy, nếu tôi muốn kiểm tra kết quả sau này (thậm chí có thể trong một quy trình khác), tốt hơn hết là tôi nên tự triển khai? Lưu trữ kết quả vào cơ sở dữ liệu theo cách thủ công?
Franklin Yu

Có, tôi tách biệt việc theo dõi "mục tiêu" với việc theo dõi "nhiệm vụ". Tôi đã viết "thực hiện một phép tính phụ thuộc vào một số mục tiêu". Thông thường, "mục tiêu" cũng là một phép tính. Ví dụ: nếu tôi muốn hiển thị bài báo X cho người dùng, tôi phải chuyển đổi nó từ XML sang HTML, nhưng trước đó, tôi phải giải quyết tất cả các tham chiếu thư mục. (X giống như một bài báo trên tạp chí.) Tôi kiểm tra xem mục tiêu "bài báo X với tất cả các tham chiếu thư mục đã được giải quyết" có tồn tại hay không và sử dụng điều đó thay vì cố gắng kiểm tra trạng thái nhiệm vụ của một tác vụ Celery mà lẽ ra đã tính được mục tiêu tôi muốn.
Louis

Và thông tin "bài báo X với tất cả các tham chiếu thư mục đã được giải quyết" được lưu trong bộ nhớ đệm và được lưu trong cơ sở dữ liệu eXist-db.
Louis

61

Mọi Taskđối tượng đều có một thuộc .requesttính, chứa AsyncRequestđối tượng đó . Theo đó, dòng sau cung cấp trạng thái của một Nhiệm vụ task:

task.AsyncResult(task.request.id).state

2
Có cách nào để lưu trữ phần trăm tiến độ của một nhiệm vụ không?
Patrick

4
Khi tôi thực hiện việc này, tôi sẽ nhận được Kết quả không đồng bộ hóa PENDING vĩnh viễn, ngay cả khi tôi đợi đủ lâu để tác vụ kết thúc. Có cách nào để làm cho điều này thấy thay đổi trạng thái không? Tôi tin rằng chương trình phụ trợ của tôi đã được định cấu hình và tôi đã thử đặt CELERY_TRACK_STARTED = True to no avail.
dstromberg

1
@dstromberg Rất tiếc, đã 4 năm kể từ khi vấn đề này xảy ra với tôi, vì vậy tôi không thể giúp gì được. Bạn gần như chắc chắn cần phải cấu hình cần tây để theo dõi trạng thái.
Marcin

16

Bạn cũng có thể tạo các trạng thái tùy chỉnh và cập nhật việc thực thi tác vụ định tuyến giá trị của nó. Ví dụ này là từ tài liệu:

@app.task(bind=True)
def upload_files(self, filenames):
    for i, file in enumerate(filenames):
        if not self.request.called_directly:
            self.update_state(state='PROGRESS',
                meta={'current': i, 'total': len(filenames)})

http://celery.readthedocs.org/en/latest/userguide/tasks.html#custom-states


11

Câu hỏi cũ nhưng gần đây tôi đã gặp phải vấn đề này.

Nếu bạn đang cố gắng nhận task_id, bạn có thể làm như sau:

import celery
from celery_app import add
from celery import uuid

task_id = uuid()
result = add.apply_async((2, 2), task_id=task_id)

Bây giờ bạn biết chính xác task_id là gì và bây giờ có thể sử dụng nó để lấy AsyncResult:

# grab the AsyncResult 
result = celery.result.AsyncResult(task_id)

# print the task id
print result.task_id
09dad9cf-c9fa-4aee-933f-ff54dae39bdf

# print the AsyncResult's status
print result.status
SUCCESS

# print the result returned 
print result.result
4

3
Hoàn toàn không cần tạo ID tác vụ của riêng bạn và chuyển nó cho apply_async. Đối tượng được trả về apply_async là một AsyncResultđối tượng, có id của nhiệm vụ mà Celery đã tạo.
Louis

1
Hãy sửa cho tôi nếu tôi sai, nhưng đôi khi việc tạo UUID dựa trên một số đầu vào có hữu ích không để tất cả các lệnh gọi nhận cùng đầu vào nhận được cùng một UUID? IOW, đôi khi có thể hữu ích khi chỉ định task_id của bạn.
dstromberg

1
@dstromberg Câu hỏi mà OP hỏi là "làm cách nào để kiểm tra trạng thái nhiệm vụ" và câu trả lời ở đây là "Nếu bạn đang cố lấy task_id ...". Không kiểm tra trạng thái nhiệm vụ, không task_idyêu cầu bạn phải tự tạo id nhiệm vụ. Trong nhận xét của mình, bạn đã tưởng tượng ra một lý do vượt xa "cách tôi kiểm tra trạng thái nhiệm vụ" và "Nếu bạn đang cố gắng nhận task_id ...` Thật tuyệt nếu bạn có nhu cầu đó nhưng không phải vậy tại đây. (Ngoài ra, việc sử dụng uuid()để tạo id nhiệm vụ hoàn toàn không có gì ngoài những gì Celery làm theo mặc định.)
Louis

Tôi đồng ý rằng OP đã không hỏi cụ thể cách lấy các ID nhiệm vụ có thể dự đoán được, nhưng câu trả lời cho câu hỏi của OP hiện là "theo dõi ID nhiệm vụ và thực hiện x". Đối với tôi, có vẻ như việc theo dõi ID tác vụ là không thực tế trong nhiều trường hợp khác nhau nên câu trả lời đó có thể không thực sự thỏa đáng. Câu trả lời này giúp tôi giải quyết trường hợp sử dụng của mình (nếu tôi có thể vượt qua các hạn chế đã lưu ý khác) vì cùng một lý do mà @dstromberg chỉ ra - cho dù nó có được thúc đẩy vì lý do đó hay không.
claytond


1

Câu trả lời của năm 2020:

#### tasks.py
@celery.task()
def mytask(arg1):
    print(arg1)

#### blueprint.py
@bp.route("/args/arg1=<arg1>")
def sleeper(arg1):
    process = mytask.apply_async(args=(arg1,)) #mytask.delay(arg1)
    state = process.state
    return f"Thanks for your patience, your job {process.task_id} \
             is being processed. Status {state}"

0

Thử:

task.AsyncResult(task.request.id).state

điều này sẽ cung cấp trạng thái Nhiệm vụ Cần tây. Nếu Celery Task đã ở trạng thái FAILURE, nó sẽ đưa ra một Exception:

raised unexpected: KeyError('exc_type',)



0

Tôi tìm thấy thông tin hữu ích trong

Hướng dẫn Công nhân Dự án Cần tây

Đối với trường hợp của tôi, tôi đang kiểm tra xem Celery có đang chạy hay không.

inspect_workers = task.app.control.inspect()
if inspect_workers.registered() is None:
    state = 'FAILURE'
else:
    state = str(task.state) 

Bạn có thể chơi với thanh tra để có được nhu cầu của bạn.


0
  • Đầu tiên , trong ứng dụng cần tây của bạn :

vi my_celery_apps / app1.py

app = Celery(worker_name)
  • và tiếp theo, chuyển sang ứng dụng nhập tệp tác vụ từ mô-đun ứng dụng cần tây của bạn.

vi nhiệm vụ / task1.py

from my_celery_apps.app1 import app

app.AsyncResult(taskid)

try:
   if task.state.lower() != "success":
        return
except:
    """ do something """


-1

Ngoài cách tiếp cận theo chương trình ở trên Sử dụng trạng thái Tác vụ Hoa có thể dễ dàng thấy.

Giám sát thời gian thực bằng Sự kiện cần tây. Flower là một công cụ dựa trên web để theo dõi và quản lý các cụm Cần tây.

  1. Tiến độ và lịch sử công việc
  2. Khả năng hiển thị chi tiết nhiệm vụ (đối số, thời gian bắt đầu, thời gian chạy và hơn thế nữa)
  3. Đồ thị và thống kê

Tài liệu chính thức: Công cụ giám sát Hoa - Cần tây

Cài đặt:

$ pip install flower

Sử dụng:

http://localhost:5555

-1
res = method.delay()
    
print(f"id={res.id}, state={res.state}, status={res.status} ")

print(res.get())

2
Vui lòng không chỉ đăng mã dưới dạng câu trả lời, mà hãy cung cấp lời giải thích mã của bạn làm gì và cách nó giải quyết vấn đề của câu hỏi. Các câu trả lời kèm theo lời giải thích thường hữu ích hơn và có chất lượng tốt hơn, đồng thời có nhiều khả năng thu hút sự ủng hộ hơn.
Mark Rotteveel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.