当我们重新启动或部署时,我们会在失败的队列中使用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
我认为可能会在这两个例外情况下自动重试?但似乎不是。
所以我猜两个问题:
Resque::TermException
手动救援,并使用它来重新安排工作。但对于所有工作,是否有一种干净的方法可以做到这一点?甚至是猴子补丁。谢谢!
编辑:在不到10秒的时间内完成所有工作,这在规模上似乎是不合理的。在运行Resque :: DirtyExit异常时,似乎需要有一种自动重新排队这些作业的方法。
答案 0 :(得分:4)
我也遇到了这个问题。事实证明,Heroku不仅向父进程发送SIGTERM
信号,而且向所有分叉进程发送信号。这不是Resque期望导致跳过RESQUE_PRE_SHUTDOWN_TIMEOUT
的逻辑,强制执行作业而没有任何时间尝试完成作业。
Heroku在发出SIGTERM
后让工人30多人正常关闭。在大多数情况下,如果作业无法完成,那么就有足够的时间来完成一项剩余缓冲时间以将作业重新排列为Resque的作业。但是,对于所有这些时间的使用,您需要设置RESQUE_PRE_SHUTDOWN_TIMEOUT
和RESQUE_TERM_TIMEOUT
env变量以及补丁Resque以正确响应发送到分叉进程的SIGTERM
。
这是一个修补resque的宝石,并更详细地解释了这个问题:
答案 1 :(得分:1)
你的resque工作需要超过10秒才能完成吗?如果在初始SIGTERM发送后10秒内完成作业,您应该没问题。尝试将作业分解为更快完成的小块。
此外,您可以让您的员工重新排队这样的工作:https://gist.github.com/mrrooijen/3719427
答案 2 :(得分:1)
- 我们可以在每个作业中手动救出Resque :: TermException,并使用它来重新安排作业。但是有一个干净的方法 这适用于所有工作?甚至是猴子补丁。
醇>
使用Resque::DirtyExit
信号杀死作业时会引发SIGTERM
异常。作业没有机会像read here那样捕获异常。
- 不应该重新尝试自动重试这些吗?你能想出它为什么不会成为什么原因吗?
醇>
不知道为什么它不应该,调度程序是否正在运行?如果不是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
这个解决方案显然不是最理想的,但到目前为止,这是我发现重试这些工作的最佳解决方案。