从Heroku上的Resque :: TermException或SIGTERM中彻底恢复

时间:2013-02-25 19:09:52

标签: heroku resque resque-retry

当我们重新启动或部署时,我们会在失败的队列中使用Resque::TermException (SIGTERM)Resque::DirtyExit获得许多Resque作业。

我们在Procfile中使用了新的TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10,因此我们的工作线看起来像:

worker:  TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10 bundle exec rake environment resque:work QUEUE=critical,high,low

我们也在使用resque-retry我认为可能会在这两个例外情况下自动重试?但似乎不是。

所以我猜两个问题:

  1. 我们可以在每个工作中从Resque::TermException手动救援,并使用它来重新安排工作。但对于所有工作,是否有一种干净的方法可以做到这一点?甚至是猴子补丁。
  2. 不应重新尝试自动重试这些?你能想出它为什么不会出现的原因吗?
  3. 谢谢!

    编辑:在不到10秒的时间内完成所有工作,这在规模上似乎是不合理的。在运行Resque :: DirtyExit异常时,似乎需要有一种自动重新排队这些作业的方法。

4 个答案:

答案 0 :(得分:4)

我也遇到了这个问题。事实证明,Heroku不仅向父进程发送SIGTERM信号,而且向所有分叉进程发送信号。这不是Resque期望导致跳过RESQUE_PRE_SHUTDOWN_TIMEOUT的逻辑,强制执行作业而没有任何时间尝试完成作业。

Heroku在发出SIGTERM后让工人30多人正常关闭。在大多数情况下,如果作业无法完成,那么就有足够的时间来完成一项剩余缓冲时间以将作业重新排列为Resque的作业。但是,对于所有这些时间的使用,您需要设置RESQUE_PRE_SHUTDOWN_TIMEOUTRESQUE_TERM_TIMEOUT env变量以及补丁Resque以正确响应发送到分叉进程的SIGTERM

这是一个修补resque的宝石,并更详细地解释了这个问题:

https://github.com/iloveitaly/resque-heroku-signals

答案 1 :(得分:1)

你的resque工作需要超过10秒才能完成吗?如果在初始SIGTERM发送后10秒内完成作业,您应该没问题。尝试将作业分解为更快完成的小块。

此外,您可以让您的员工重新排队这样的工作:https://gist.github.com/mrrooijen/3719427

答案 2 :(得分:1)

  
      
  1. 我们可以在每个作业中手动救出Resque :: TermException,并使用它来重新安排作业。但是有一个干净的方法   这适用于所有工作?甚至是猴子补丁。
  2.   

使用Resque::DirtyExit信号杀死作业时会引发SIGTERM异常。作业没有机会像read here那样捕获异常。

  
      
  1. 不应该重新尝试自动重试这些吗?你能想出它为什么不会成为什么原因吗?
  2.   

不知道为什么它不应该,调度程序是否正在运行?如果不是rake resque:scheduler

我写了一篇关于我最近使用Resque::DirtyExit时遇到的一些问题的详细博文,也许它很有用=> Understanding the Resque internals – Resque::DirtyExit unveiled

答案 3 :(得分:0)

在没有找到可靠解决方案的情况下,我也一直在努力解决这个问题。

我发现的少数解决方案之一就是按计划运行rake任务(每1分钟执行一次cron作业),查找Resque :: DirtyExit失败的作业,重试这些特定作业并从故障队列中删除这些作业

以下是rake任务的示例 https://gist.github.com/CharlesP/1818418754aec03403b3

这个解决方案显然不是最理想的,但到目前为止,这是我发现重试这些工作的最佳解决方案。