2015-04-26 14 views
18

Ho fatto un sacco di ricerche su questo, e sono sorpreso di non aver trovato una buona risposta a questo ancora da nessuna parte.Cattura Heroku SIGTERM in lavoratori di Celery per spegnere il lavoratore con grazia

Sto eseguendo una grande applicazione su Heroku e ho alcune attività di sedici che vengono eseguite per un'elaborazione molto lunga, e alla fine dell'attività salvare un risultato. Ogni volta che effettuo il reimpiego su Heroku, invia SIGTERM (e alla fine SIGKILL) e uccide il mio lavoratore in esecuzione. Sto cercando di trovare un modo per l'istanza di lavoro di chiudersi in modo corretto e ri-accodare se stesso per l'elaborazione successiva in modo che alla fine possiamo salvare il risultato richiesto invece di perdere l'attività in coda.

Non riesco a trovare un modo che funzioni per consentire all'operatore di ascoltare SIGTERM correttamente. Il più vicino che ho ottenuto, che funziona quando si esegue python manage.py celeryd direttamente, ma NON per l'emulazione di Heroku utilizza caposquadra, è la seguente:

@app.task(bind=True, max_retries=1) 
def slow(self, x): 
    try: 
     for x in range(100): 
      print 'x: ' + unicode(x) 
      time.sleep(10) 
    except exceptions.MaxRetriesExceededError: 
     logger.error('whoa') 
    except (exceptions.WorkerShutdown, exceptions.WorkerTerminate) as exc: 
     logger.error(u'retrying, ' + unicode(exc)) 
     raise self.retry(exc=exc, countdown=10) 
    except (KeyboardInterrupt, SystemExit) as exc: 
     print 'retrying' 
     raise self.retry(exc=exc, countdown=10) 
    else: 
     return x 
    finally: 
     logger.info('task ended!') 

Quando inizio a questo compito sedano in esecuzione all'interno di caposquadra e premere CTRL + C, il succede questo:

^CSIGINT received 
22:20:59 system | sending SIGTERM to all processes 
22:20:59 web.1 | exited with code 0 
22:21:04 system | sending SIGKILL to all processes 
Killed: 9 

Quindi è chiaro che nessuna delle eccezioni sedano, né i KeyboardInterrupt o SystemExit eccezioni che ho visto in altri post, prendere correttamente SIGTERM e spegnere il lavoratore.

Qual è il modo giusto per farlo?

+0

http://celery.readthedocs.org/en/latest/userguide/workers.html?highlight=sigkill#process-signals sembra indicare che l'operatore principale intercetterà sempre SIGTERM. –

+0

Giusto - quindi c'è un modo per far propagare il lavoratore principale ai bambini? – jdotjdot

+0

Questo è un problema che non ho mai trovato un'ottima soluzione. Tendo a gestirlo in logica applicativa assicurandomi che i miei compiti siano idempotenti e il tracciamento delle attività avviate e completate in modo tale da consentire il riavvio automatico di una determinata attività all'avvio dell'applicazione. –

risposta

2

il sedano purtroppo non è stato progettato per effettuare l'arresto pulito. MAI. Voglio dire che. i lavoratori di celery rispondono a SIGTERM ma se un'attività è incompleta, i processi di lavoro aspetteranno di terminare l'attività e solo allora di uscire. In tal caso, puoi inviarlo SIGKILL se gli addetti non si spengono in un tempo ragionevole, ma in questo caso si verificherà una perdita di informazioni, quindi potresti non sapere quali lavori sono rimasti incompleti.

+0

Come è possibile mantenere il risultato dell'attività, pertanto dovrebbe essere possibile verificare lo stato dell'attività ecc. A livello di applicazione e ripristinare la situazione. –

0

È possibile utilizzare acks_late o task_acks_late.

Le attività verranno confermate dalla coda dopo l'attività eseguita e non solo in precedenza. Quindi l'attività verrà respawn se il lavoratore si spegnerà con garbo.

Problemi correlati