【问题标题】:How to restart Celery gracefully without delaying tasks如何在不延迟任务的情况下优雅地重启 Celery
【发布时间】:2012-03-27 09:53:40
【问题描述】:

我们使用 Celery 和 Django webapp 来管理离线任务;其中一些任务可以运行长达 120 秒。

每当我们进行任何代码修改时,我们都需要重新启动 Celery 以让它重新加载新的 Python 代码。我们当前的解决方案是向 Celery 主进程 (kill -s 15 `cat /var/run/celeryd.pid`) 发送一个 SIGTERM,然后等待它死亡并重新启动它 (python manage.py celeryd --pidfile=/var/run/celeryd.pid [...])。

由于长时间运行的任务,这通常意味着关闭将需要一两分钟,在此期间不会处理任何新任务,从而对当前在站点上的用户造成明显的延迟。我正在寻找一种方法来告诉 Celery 关闭,然后立即启动一个新的 Celery 实例以开始运行新任务。

不起作用的事情:

  • 向主进程发送 SIGHUP:这导致 Celery 尝试通过热关机然后重新启动自身来“重新启动”。这不仅需要很长时间,甚至不起作用,因为显然新进程在旧进程死亡之前启动,所以新进程抱怨ERROR: Pidfile (/var/run/celeryd.pid) already exists. Seems we're already running? (PID: 13214) 并立即死亡。 (这看起来像是 Celery 本身的一个错误;我已经 let them know 关于它。)
  • 向主进程发送 SIGTERM,然后立即启动一个新实例:与 Pidfile 相同的问题。
  • 完全禁用 Pidfile:没有它,我们无法确定 30 个 Celery 进程中的哪一个是当我们希望它进行热关闭时需要发送 SIGTERM 的主进程。我们也没有可靠的方法来检查主进程是否还活着。

【问题讨论】:

标签: django linux celery pid celeryd


【解决方案1】:

我想你可以试试这个:

kill -s HUP ``cat /var/run/celeryd.pid`` 
python manage.py celeryd --pidfile=/var/run/celeryd.pid

HUP 可以回收每个空闲的工人,让执行工人继续运行,HUP 会让这些工人得到信任。然后你可以安全地重新启动一个新的 celery worker 主进程和 worker。任务完成后,老工人可能会被杀死。

我在我们的生产中使用过这种方式,现在看起来很安全。希望对您有所帮助!

【讨论】:

    【解决方案2】:

    有点晚了,但可以通过删除名为 celerybeat.pid 的文件来解决。

    为我工作

    【讨论】:

      【解决方案3】:

      我最近用 SIGHUP 修复了这个错误:https://github.com/celery/celery/pull/662

      【讨论】:

      • 谢谢!但是,您的修复并没有改变 SIGHUP 在终止和重新启动之前等待所有任务完成的事实,这再次导致我试图避免的延迟。关于如何利用您的修复并使其无需等待即可重新启动的想法会很棒......
      • 这就是我解决问题的方法。我将每个长时间运行的任务(视频转换、电子邮件发送)放在一个单独的队列中,由单独的工作人员处理。因此,当我向所有工作人员发送 SIGHUP 时,我知道来自默认队列的工作人员处理任务不会长时间阻塞,因为只有小任务。视频转换不会阻止小任务。只有视频转换队列被阻塞了一段时间。但这在我的情况下是可以接受的。
      • 所以经过一些测试,我发现您的修复也修复了 SIGTERM 问题。因此,我终于设法通过合并您的修复程序并使用以下命令重新启动 Celery,一劳永逸地解决了这个问题:kill -s SIGTERM ``cat /var/run/celeryd.pid`` && python manage.py celeryd --pidfile=/var/run/celeryd.pid [...] 如果您可以将其放入您的答案中,我会接受!
      • 我认为这是不可靠的行为。我的补丁有一个小错误——它过早地释放了一个 pidlock(在所有任务完成之前)。因此,它允许在旧进程完全关闭之前启动新进程。这是完全不可靠的。当合并到主分支时,这是固定的。您所说的 SIGTERM 错误并不是真正的错误。这只是每个守护进程的正常行为。所以我强烈建议不要利用补丁中的错误,而是使用固定版本:github.com/ask/celery/commit/…
      【解决方案4】:

      您使用 SIGHUP (1) 来热关闭 celery。我不确定它是否真的会导致热关机。但是 SIGINT (2) 会导致热关机。尝试使用 SIGINT 代替 SIGHUP,然后在您的脚本中手动启动 celery(我猜)。

      【讨论】:

        【解决方案5】:
        rm *.pyc
        

        这会导致重新加载更新的任务。我最近发现了这个技巧,我只是希望没有讨厌的副作用。

        【讨论】:

          【解决方案6】:

          celeryd 有 --autoreload 选项。如果启用,celery worker(主进程)将检测 celery 模块的变化并重新启动所有工作进程。与 SIGHUP 信号相反,autoreload 在当前执行任务完成时独立地重新启动每个进程。这意味着当一个工作进程重新启动时,其余进程可以执行任务。

          http://celery.readthedocs.org/en/latest/userguide/workers.html#autoreloading

          【讨论】:

          【解决方案7】:

          您可以使用自定义 pid 文件名启动它吗?可能带有时间戳,并关闭它以知道要杀死哪个 PID?

          CELERYD_PID_FILE="/var/run/celery/%n_{timestamp}.pid"

          ^我不知道时间戳语法,但也许你知道或者你能找到它?

          然后使用当前系统时间来杀死任何旧的 pid 并启动一个新的?

          【讨论】:

          • 我怀疑您需要将问题中的一种技术与此结合起来。根据您的代理,您应该能够使用基于时间戳的 pidfile(使用--pidfile=)启动一个新的 celery,然后将SIGTERM 发送到所有其他正在运行的 celery 进程以使它们热关机(尽管请注意真的应该只有一个,除非你在旧 celeryd 仍在热关机时尝试这个)。
          猜你喜欢
          • 1970-01-01
          • 2018-07-06
          • 2011-03-22
          • 1970-01-01
          • 2020-02-06
          • 2019-10-23
          • 1970-01-01
          • 1970-01-01
          • 2022-01-20
          相关资源
          最近更新 更多