在 Celery 工作线程中捕获 Heroku SIGTERM 以优雅地关闭工作线程

2024-04-28

我对此进行了大量研究,令我惊讶的是我还没有在任何地方找到一个好的答案。

我正在 Heroku 上运行一个大型应用程序,并且我有某些运行很长时间处理的 celery 任务,并在任务结束时保存结果。每次我在 Heroku 上重新部署时,它都会发送 SIGTERM(最终发送 SIGKILL)并杀死我正在运行的工作线程。我正在尝试找到一种方法,让工作实例优雅地关闭自身并重新排队以供稍后处理,以便最终我们可以保存所需的结果而不是丢失排队的任务。

我找不到一种方法可以让工作人员正确监听 SIGTERM。我得到的最接近的,在跑步时有效python manage.py celeryd直接但是NOT使用 foreman 模拟 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!')

当我启动在 foreman 中运行的 celery 任务并按 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 or SystemExit我在其他帖子中看到的异常,正确捕获 SIGTERM 并关闭工作线程。

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


从版本 >= 4 开始,Celery 附带了一个专门针对 Heroku 的特殊功能,可以开箱即用地支持此功能:

$ REMAP_SIGTERM=SIGQUIT celery -A proj worker -l info

source: https://devcenter.heroku.com/articles/celery-heroku#using-remap_sigterm https://devcenter.heroku.com/articles/celery-heroku#using-remap_sigterm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Celery 工作线程中捕获 Heroku SIGTERM 以优雅地关闭工作线程 的相关文章

随机推荐