Я провел массу исследований по этому вопросу, и я удивлен, что еще нигде не нашел хорошего ответа на этот вопрос.
Я запускаю большое приложение на Heroku, и у меня есть определенные задачи сельдерея, которые очень долго обрабатываются и в конце задачи сохраняют результат. Каждый раз, когда я переустанавливаю Heroku, он отправляет SIGTERM (и, в конечном итоге, SIGKILL) и убивает моего работающего воркера. Я пытаюсь найти способ для рабочего экземпляра корректно завершить работу и повторно поставить себя в очередь для обработки позже, чтобы в конечном итоге мы могли сохранить требуемый результат, а не потерять поставленную в очередь задачу.
Я не могу найти способ, чтобы рабочий правильно прослушивал SIGTERM. Самое близкое, что я получил, которое работает при запуске python manage.py celeryd
напрямую, но НЕ при эмуляции Heroku с использованием мастера, это следующее:
@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!')
Когда я запускаю эту задачу сельдерея, работающую в мастере, и нажимаю Ctrl + C, происходит следующее:
^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
Таким образом, ясно, что ни одно из исключений сельдерея, ни исключения KeyboardInterrupt
или SystemExit
, которые я видел в других сообщениях, должным образом не перехватывают SIGTERM и не завершают рабочий процесс.
Как правильно это сделать?