在芹菜工作者中捕获Heroku SIGTERM以优雅地关闭工作人员

时间:2015-04-26 02:27:56

标签: python heroku rabbitmq celery sigterm

我已经对此做了大量的研究,我很惊讶我还没有找到一个好的答案。

我正在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

所以很明显,没有芹菜例外,我在其他帖子中看到的KeyboardInterruptSystemExit例外,都没有正确地抓住SIGTERM并关闭工人。

这样做的正确方法是什么?

3 个答案:

答案 0 :(得分:1)

不幸的是,芹菜不是为干净关闭而设计的。 EVER。我是认真的。芹菜工作者响应SIGTERM,但如果任务不完整,工作进程将等待完成任务,然后才退出。在这种情况下,如果工人在合理的时间内没有关闭,你可以发送SIGKILL,但在这种情况下会丢失信息,即你​​可能不知道哪些工作仍然不完整。

答案 1 :(得分:0)

您可以使用acks_latetask_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