Як перевірити статус завдання в Celery?


92

Як перевірити, чи виконується завдання у селері (зокрема, я використовую celery-django)?

Я прочитав документацію і погуглив, але не можу побачити такий виклик:

my_example_task.state() == RUNNING

Моїм випадком використання є те, що я маю зовнішню службу (java) для перекодування. Коли я надсилаю документ для перекодування, я хочу перевірити, чи виконується завдання, яке запускає цю службу, а якщо ні - (повторно) запустити його.

Я використовую поточні стабільні версії - 2.4, я вважаю.

Відповіді:


97

Поверніть task_id (який подано з .delay ()) і запитайте пізніше екземпляр селери про стан:

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

Запитуючи, отримайте новий AsyncResult, використовуючи цей task_id:

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

10
Дякую, але що, якщо у мене немає доступу x?
Марцін

4
Куди ви ставите свою роботу в селеру? Там вам потрібно повернути task_id, щоб відстежувати роботу в майбутньому.
Грегор

На відміну від @ Marcin's, ця відповідь не використовує статичний метод Task.AsyncResult () як фабрику AsyncResult, який корисно повторно використовує конфігурацію бекенда, інакше виникає помилка при спробі отримати результат.
ArnauOrriols

2
@Chris Суперечка з кодом @gregor полягає у створенні async_result. У вашому випадку використання у вас вже є примірник, ви готові піти. Але що трапиться, якщо у вас є лише ідентифікатор завдання і вам потрібно створити екземпляр async_resultекземпляра, щоб мати можливість викликати async_result.get()? Це примірник AsyncResultкласу, але ви не можете використовувати необроблений клас celery.result.AsyncResult, вам потрібно отримати клас із функції, обгорнутої app.task(). У вашому випадку ви це зробитеasync_result = run_instance.AsyncResult('task-id')
ArnauOrriols

1
but you cannot use the raw class celery.result.AsyncResult, you need to get the class from the function wrapped by app.task(). - Думаю, саме так насправді його мали використовувати. Прочитайте код: github.com/celery/celery/blob/…
nevelis

70

Створення AsyncResultоб’єкта з ідентифікатора завдання - це спосіб, рекомендований у FAQ, для отримання статусу завдання, коли єдиним, що у вас є, є ідентифікатор завдання.

Однак станом на Селера 3.x є суттєві застереження, які можуть вкусити людей, якщо вони не звернуть на них уваги. Це насправді залежить від конкретного сценарію використання.

За замовчуванням Celery не реєструє "запущений" стан.

Щоб Celery міг записати, що завдання виконується, потрібно встановити task_track_startedзначення True. Ось просте завдання, яке перевіряє це:

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

Коли task_track_startedє False, що є типовим, показ стану є PENDINGнавіть незважаючи на те, що завдання розпочато. Якщо ви встановите task_track_startedна True, то стан буде STARTED.

Держава PENDINGозначає "я не знаю".

Спілка AsyncResultз державою PENDINGне означає нічого більше, ніж те, що Селера не знає статусу завдання. Це може бути з будь-якої кількості причин.

З одного боку, їх AsyncResultможна створити з недійсними ідентифікаторами завдань. Такі "завдання" будуть визнані на розгляді Селері:

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

Гаразд, значить, ніхто не збирається подавати очевидно недійсні ідентифікатори AsyncResult. Досить справедливо, але це також має ефект, який AsyncResultтакож розглядатиме завдання, яке успішно виконано, але про яке Селера забув як таке PENDING. Знову ж таки, у деяких сценаріях використання це може бути проблемою. Частина проблеми залежить від того, як Celery налаштовано на збереження результатів завдань, оскільки це залежить від наявності "надгробків" у сервісі результатів. ("Надгробки" - це термін використання в документації Celery для фрагментів даних, які фіксують, як закінчилося завдання.) Використання AsyncResultвзагалі не буде працювати, якщо task_ignore_resultє True. Більш неприємна проблема полягає в тому, що Селера за замовчуванням закінчує термін дії надгробків. result_expiresналаштування за замовчуванням встановлено на 24 години. Отже, якщо ви запустите завдання і запишете ідентифікатор у довготривалому сховищі, а через 24 години ви створите за AsyncResultдопомогою нього, статус буде PENDING.

Всі "реальні завдання" починаються в PENDINGштаті. Отже, отримання PENDINGзавдання може означати, що завдання було запитане, але ніколи не прогресувало далі (з якоїсь причини). Або це може означати, що завдання виконано, але Селера забув свій стан.

Ой! AsyncResultне буде працювати для мене. Що ще я можу зробити?

Я вважаю за краще відстежувати цілі, ніж відстежувати самі завдання . Я зберігаю деяку інформацію про завдання, але це справді другорядне для відстеження цілей. Цілі зберігаються в сховищі, незалежному від Селери. Коли запиту потрібно виконати обчислення, залежить від досягнення якоїсь мети, він перевіряє, чи ціль вже досягнута, якщо так, тоді він використовує цю кешовану мету, інакше запускає завдання, яке вплине на ціль, і надсилає до клієнт, який зробив запит HTTP, відповідь, яка вказує, що він повинен почекати результату.


Назви змінних та гіперпосилання наведені вище для Celery 4.x. У 3.x відповідні змінні і гіперпосилання: CELERY_TRACK_STARTED, CELERY_IGNORE_RESULT, CELERY_TASK_RESULT_EXPIRES.


Тож, якщо я хочу перевірити результат пізніше (можливо, навіть в рамках іншого процесу), мені краще з власною реалізацією? Зберігання результату в базі даних вручну?
Франклін Ю

Так, я б відокремив відстеження "мети" від відстеження "завдань". Я писав "виконати обчислення, яке залежить від певної мети". Зазвичай "мета" - це також обчислення. Наприклад, якщо я хочу показати статтю X користувачеві, я повинен перетворити її з XML в HTML, але перед цим я повинен вирішити всі бібліографічні посилання. (X схожий на статтю журналу.) Я перевіряю, чи існує ціль «стаття X з усіма бібліографічними посиланнями вирішеними», і використовую це, а не намагаюся перевірити статус завдання завдання Celery, яке обчислило б ціль, яку я хочу.
Луї

А інформація "стаття X з усіма бібліографічними посиланнями" зберігається в кеші пам'яті та зберігається в базі даних eXist-db.
Луї

61

Кожен Taskоб'єкт має .requestвластивість, яка містить його AsyncRequestоб'єкт. Відповідно, такий рядок надає стан Завдання task:

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

2
Чи є спосіб зберегти відсоток прогресу завдання?
Патрік

4
Коли я це роблю, я отримую постійно ОЧАКУЮЧИЙ AsyncResult, навіть якщо я чекаю досить довго, поки завдання закінчиться. Чи є спосіб зробити так, щоб це бачило зміни стану? Я вважаю, що мій сервер налаштований, і я спробував встановити CELERY_TRACK_STARTED = True безрезультатно.
dstromberg

1
@dstromberg На жаль, минуло 4 роки, як це стало проблемою для мене, тому я не можу допомогти. Вам майже напевно потрібно налаштувати селеру для відстеження стану.
Marcin

16

Ви також можете створювати власні стани та оновлювати виконання завдання, що визначає значення. Цей приклад з документації:

@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

Старе питання, але нещодавно я зіткнувся з цією проблемою.

Якщо ви намагаєтеся отримати task_id, ви можете зробити це так:

import celery
from celery_app import add
from celery import uuid

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

Тепер ви точно знаєте, що таке task_id, і тепер можете використовувати його для отримання 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
Немає необхідності створювати власний ідентифікатор завдання та передавати його apply_async. Об'єкт, що повертається, apply_async є AsyncResultоб'єктом, який має ідентифікатор завдання, яке створило Celery.
Луї

1
Виправте мене, якщо я помиляюся, але чи не часом корисно генерувати UUID на основі деяких входів, щоб усі дзвінки, що отримують однакові входи, отримували однаковий UUID? IOW, можливо, іноді корисно вказати свій task_id.
dstromberg

1
@dstromberg Запитання, яке ставить OP, - "як мені перевірити статус завдання", а відповідь тут говорить "Якщо ви намагаєтесь отримати task_id ...". Ні перевірка стану завдання, ні отримання не task_idвимагають, щоб ви самі генерували ідентифікатор завдання. У своєму коментарі ви уявили причину, яка виходить за рамки "як мені перевірити статус завдання" та "Якщо ви намагаєтеся отримати task_id ...` Чудово, якщо у вас є така потреба, але це не так тут. (Крім того, використання uuid()для створення ідентифікатора завдання не робить абсолютно нічого, крім того, що робить Селера за замовчуванням.)
Луїс

Я погоджуюсь з тим, що операційна програма спеціально не запитувала, як отримати передбачувані ідентифікатори завдань, але відповідь на запитання оперативної програми наразі: "відстежувати ідентифікатор завдання та робити x". Мені здається, що відстеження ідентифікатора завдання є недоцільним у найрізноманітніших ситуаціях, тому відповідь може насправді не бути задовільною. Ця відповідь допомагає мені вирішити мій випадок використання (якщо я можу подолати інші зазначені обмеження) з тієї ж причини @dstromberg вказує - незалежно від того, мотивована вона з цієї причини.
claytond


1

Відповідь 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

Спробуйте:

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

це забезпечить статус Завдання Селери. Якщо завдання Селера вже перебуває у стані ПОМИЛКИ, воно видасть виняток:

raised unexpected: KeyError('exc_type',)


0

для простих завдань ми можемо використовувати http://flower.readthedocs.io/en/latest/screenshots.html та http://policystat.github.io/jobtastic/ для моніторингу.

а для складних завдань скажіть завдання, яке має справу з багатьма іншими модулями. Ми рекомендуємо вручну записати хід і повідомлення на конкретному блоці завдань.


0

Я знайшов корисну інформацію в

Керівництво працівників проекту з селери інспектування робітників

Для мого випадку я перевіряю, чи працює Селера.

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

Ви можете пограти з inspect, щоб отримати свої потреби.


0
  • Перший , у вашому додатку на селеру:

vi my_celery_apps / app1.py

app = Celery(worker_name)
  • а далі перейдіть до файлу завдання , імпортуйте додаток із модуля програми селери.

vi tasks / task1.py

from my_celery_apps.app1 import app

app.AsyncResult(taskid)

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


-1

Окрім вищезазначеного, Програмний підхід дозволяє легко побачити стан використання квіткових завдань.

Моніторинг у реальному часі за допомогою подій Celery. Flower - це веб-інструмент для моніторингу та адміністрування кластерів селери.

  1. Хід завдання та історія
  2. Можливість показу деталей завдання (аргументи, час запуску, час виконання тощо)
  3. Графіки та статистика

Офіційний документ: Квітка - інструмент моніторингу селери

Встановлення:

$ pip install flower

Використання:

http://localhost:5555

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

print(res.get())

2
Будь ласка, не публікуйте лише код як відповідь, але також надайте пояснення, що робить ваш код і як він вирішує проблему питання. Відповіді з поясненнями, як правило, є більш корисними та якісними, і, швидше за все, приваблюють голосів.
Марк Роттевель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.