我已经对此做了大量的研究,我很惊讶我还没有找到一个好的答案。
我正在Heroku上运行一个大型应用程序,我有一些芹菜任务运行了很长时间的处理,并在任务结束时保存结果。每次我在Heroku上重新部署时,它都会发送SIGTERM(最终是SIGKILL)并杀死我的跑步工作者。我正在尝试找到一种方法让工作者实例优雅地自行关闭并重新排队以便稍后处理,这样我们最终可以保存所需的结果,而不是丢失排队的任务。
我找不到让工作人员正确监听SIGTERM的方法。我得到的最接近的,在使用工头模拟Heroku时直接运行python manage.py celeryd
但不时有效,如下:
@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并关闭工人。
这样做的正确方法是什么?
答案 0 :(得分:1)
答案 1 :(得分:0)
您可以使用acks_late或task_acks_late。
任务将在执行任务后从队列确认,而不是之前。因此,如果工作人员正常关闭,任务将重新生成。
答案 2 :(得分:0)
从版本== 4开始,Celery具有一项仅针对Heroku的特殊功能,该功能开箱即用地支持此功能:
$ REMAP_SIGTERM=SIGQUIT celery -A proj worker -l info
来源:https://devcenter.heroku.com/articles/celery-heroku#using-remap_sigterm