Come controllare lo stato delle attività in Celery?


92

Come si controlla se un'attività è in esecuzione in sedano (in particolare, sto usando celery-django)?

Ho letto la documentazione e ho cercato su Google, ma non riesco a vedere una chiamata come:

my_example_task.state() == RUNNING

Il mio caso d'uso è che dispongo di un servizio esterno (java) per la transcodifica. Quando invio un documento da transcodificare, desidero verificare se l'attività che esegue quel servizio è in esecuzione e, in caso contrario, (ri) avviarla.

Sto usando le attuali versioni stabili - 2.4, credo.

Risposte:


97

Restituire task_id (che è dato da .delay ()) e chiedere successivamente all'istanza di celery sullo stato:

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

Quando lo chiedi, ottieni un nuovo AsyncResult usando questo task_id:

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

10
Grazie, ma cosa succede se non ho accesso a x?
Marcin

4
Dove metti in coda i tuoi lavori nel sedano? Lì devi restituire task_id per tenere traccia del lavoro in futuro.
Gregor,

A differenza di @ Marcin, questa risposta non utilizza il metodo statico Task.AsyncResult () come factory di AsyncResult, che riutilizza utilmente la configurazione del backend, altrimenti viene generato un errore quando si tenta di ottenere il risultato.
ArnauOrriols

2
@Chris La controversia con il codice @gregor è nell'istanza di async_result. Nel tuo caso d'uso hai già l'istanza, sei a posto. Ma cosa succede se hai solo l'ID attività e devi creare async_resultun'istanza per poter chiamare async_result.get()? Questa è un'istanza della AsyncResultclasse, ma non è possibile utilizzare la classe non elaborata celery.result.AsyncResult, è necessario ottenere la classe dalla funzione racchiusa da app.task(). Nel tuo caso lo farestiasync_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(). - Penso che questo sia il modo in cui avrebbe dovuto essere usato. Leggi il codice: github.com/celery/celery/blob/…
nevelis

70

La creazione di un AsyncResultoggetto dall'id dell'attività è il modo consigliato nelle FAQ per ottenere lo stato dell'attività quando l'unica cosa che hai è l'ID dell'attività.

Tuttavia, a partire da Celery 3.x, ci sono avvertimenti significativi che potrebbero mordere le persone se non prestano loro attenzione. Dipende davvero dallo scenario del caso d'uso specifico.

Per impostazione predefinita, Celery non registra uno stato "in esecuzione".

Al fine di sedano per registrare che un compito è in esecuzione, è necessario impostare task_track_starteda True. Ecco una semplice attività che verifica questo:

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

Quando task_track_startedè False, che è l'impostazione predefinita, lo stato mostra PENDINGanche se l'attività è iniziata. Se imposti task_track_startedsu True, lo stato saràSTARTED .

Lo stato PENDING significa "non lo so".

Un AsyncResultcon lo stato PENDINGnon significa altro che Celery non conosce lo stato del compito. Ciò potrebbe essere dovuto a diversi motivi.

Per prima cosa, AsyncResultpuò essere costruito con ID attività non validi. Tali "compiti" saranno considerati in sospeso da Celery:

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

Ok, quindi nessuno fornirà ID ovviamente non validi a AsyncResult. Abbastanza giusto, ma ha anche l'effetto che AsyncResultconsidererà anche un'attività che è stata eseguita con successo ma che Celery ha dimenticato come essere PENDING. Di nuovo, in alcuni casi d'uso questo può essere un problema. Parte del problema dipende dal modo in cui Celery è configurato per conservare i risultati delle attività, perché dipende dalla disponibilità delle "lapidi" nel backend dei risultati. ("Tombstones" è il termine utilizzato nella documentazione di Celery per i blocchi di dati che registrano il modo in cui l'attività è terminata.) L'utilizzo AsyncResultnon funzionerà affatto se task_ignore_resultèTrue . Un problema più fastidioso è che Celery fa scadere le lapidi per impostazione predefinita. Ilresult_expiresl'impostazione predefinita è impostata su 24 ore. Quindi, se avvii un'attività e registri l'id nella memoria a lungo termine e più 24 ore dopo, crei un AsyncResultcon esso, lo stato sarà PENDING.

Tutti i "compiti reali" iniziano nello PENDINGstato. Quindi PENDINGeseguire un'attività potrebbe significare che l'attività è stata richiesta ma non è mai progredita oltre (per qualsiasi motivo). Oppure potrebbe significare che l'attività è stata eseguita ma Celery ha dimenticato il suo stato.

Ahia! AsyncResultnon funzionerà per me. Cos'altro posso fare?

Preferisco tenere traccia degli obiettivi piuttosto che tenere traccia delle attività stesse . Conservo alcune informazioni sulle attività, ma è davvero secondario per tenere traccia degli obiettivi. Gli obiettivi sono conservati in un magazzino indipendente da Celery. Quando una richiesta deve eseguire un calcolo dipende dal raggiungimento di un obiettivo, controlla se l'obiettivo è già stato raggiunto, se sì, utilizza questo obiettivo memorizzato nella cache, altrimenti avvia l'attività che avrà effetto sull'obiettivo e invia a il client che ha effettuato la richiesta HTTP una risposta che indica che dovrebbe attendere un risultato.


I nomi delle variabili e i collegamenti ipertestuali sopra riportati sono per Celery 4.x. In 3.x le variabili e collegamenti corrispondenti sono: CELERY_TRACK_STARTED, CELERY_IGNORE_RESULT, CELERY_TASK_RESULT_EXPIRES.


Quindi, se voglio controllare il risultato in un secondo momento (forse anche all'interno di un altro processo), sto meglio con la mia implementazione? Memorizzare manualmente il risultato nel database?
Franklin Yu

Sì, separerei il monitoraggio degli "obiettivi" dal monitoraggio delle "attività". Ho scritto "eseguire un calcolo che dipende da un obiettivo". Di solito, l '"obiettivo" è anche un calcolo. Ad esempio, se voglio mostrare l'articolo X a un utente, devo convertirlo da XML a HTML, ma prima devo aver risolto tutti i riferimenti bibliografici. (X è come un articolo di giornale.) Controllo se l'obiettivo "articolo X con tutti i riferimenti bibliografici risolti" esiste e lo uso piuttosto che cercare di controllare lo stato dell'attività di un'attività di Celery che avrebbe calcolato l'obiettivo che desidero.
Louis

E l'informazione "articolo X con tutti i riferimenti bibliografici risolti" è archiviata in una cache di memoria e archiviata in un database eXist-db.
Louis

61

Ogni Taskoggetto ha una .requestproprietà, che lo contiene AsyncRequestoggetto. Di conseguenza, la riga seguente fornisce lo stato di un'attività task:

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

2
C'è un modo per memorizzare la percentuale di avanzamento di un'attività?
patrick

4
Quando si esegue questa operazione, ottengo un AsyncResult PENDING permanente, anche se aspetto abbastanza a lungo per il completamento dell'attività. C'è un modo per far sì che questo veda i cambiamenti di stato? Credo che il mio backend sia configurato e ho provato a impostare CELERY_TRACK_STARTED = True senza alcun risultato.
dstromberg

1
@dstromberg Sfortunatamente sono passati 4 anni da quando questo era un problema per me, quindi non posso aiutarti. Quasi sicuramente è necessario configurare il sedano per monitorare lo stato.
Marcin

16

Puoi anche creare stati personalizzati e aggiornare la sua esecuzione dell'attività di valore. Questo esempio è tratto da documenti:

@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

Vecchia domanda ma recentemente mi sono imbattuto in questo problema.

Se stai cercando di ottenere task_id, puoi farlo in questo modo:

import celery
from celery_app import add
from celery import uuid

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

Ora sai esattamente cos'è task_id e ora puoi usarlo per ottenere 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
Non è assolutamente necessario creare il proprio ID attività e passarlo a apply_async. L'oggetto restituito da apply_async è un AsyncResultoggetto, che ha l'ID dell'attività generata da Celery.
Louis,

1
Correggimi se sbaglio, ma a volte non è utile generare un UUID basato su alcuni input, in modo che tutte le chiamate che ricevono gli stessi input ottengano lo stesso UUID? IOW, forse a volte è utile specificare il tuo task_id.
dstromberg

1
@dstromberg La domanda posta dall'OP è "come posso controllare lo stato dell'attività" e la risposta qui dice "Se stai cercando di ottenere task_id ...". Né il controllo dello stato dell'attività, né la ricezione task_idrichiedono la generazione di un ID attività da soli. Nel tuo commento, hai immaginato un motivo che va al di là di "come posso controllare lo stato dell'attività" e "Se stai cercando di ottenere task_id ...` Ottimo se hai questa necessità ma non è il caso qui. (Inoltre, l'utilizzo uuid()per generare un ID attività non fa assolutamente nulla oltre a ciò che fa Celery per impostazione predefinita.)
Louis

Sono d'accordo sul fatto che l'OP non abbia chiesto specificamente come ottenere ID attività prevedibili, ma la risposta alla domanda dell'OP è attualmente "traccia l'ID attività e fai x". Mi sembra che il monitoraggio dell'ID attività non sia pratico in un'ampia varietà di situazioni, quindi la risposta potrebbe non essere effettivamente soddisfacente. Questa risposta mi aiuta a risolvere il mio caso d'uso (se riesco a superare altre limitazioni note) per lo stesso motivo per cui @dstromberg sottolinea, indipendentemente dal fatto che sia stato motivato o meno per quel motivo.
Claytond


1

Risposta del 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

Provare:

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

questo fornirà lo stato dell'attività sul sedano. Se Celery Task è già in stato di FALLIMENTO , verrà generata un'eccezione:

raised unexpected: KeyError('exc_type',)



0

Ho trovato informazioni utili nel file

Celery Project Workers Guide ispettori-lavoratori

Nel mio caso, sto controllando se Celery è in esecuzione.

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

Puoi giocare con inspect per soddisfare le tue esigenze.


0
  • Primo , nella tua APP sedano :

vi my_celery_apps / app1.py

app = Celery(worker_name)
  • e successivamente, passa al file delle attività , importa l'app dal modulo dell'app sedano.

vi task / task1.py

from my_celery_apps.app1 import app

app.AsyncResult(taskid)

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


-1

A parte l'approccio programmatico di cui sopra, lo stato di utilizzo di Flower Task può essere facilmente visto.

Monitoraggio in tempo reale tramite Celery Events. Flower è uno strumento basato sul web per il monitoraggio e l'amministrazione dei cluster di Celery.

  1. Avanzamento e cronologia delle attività
  2. Possibilità di mostrare i dettagli dell'attività (argomenti, ora di inizio, runtime e altro)
  3. Grafici e statistiche

Documento ufficiale: Fiore - Strumento di monitoraggio del sedano

Installazione:

$ pip install flower

Utilizzo:

http://localhost:5555

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

print(res.get())

2
Per favore, non pubblicare solo il codice come risposta, ma fornisci anche una spiegazione su cosa fa il tuo codice e come risolve il problema della domanda. Le risposte con una spiegazione sono generalmente più utili e di migliore qualità e hanno maggiori probabilità di attirare voti positivi.
Mark Rotteveel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.