13

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

我们TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10在 Procfile 中使用新的,所以我们的工作行看起来像:

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

我们还使用resque-retry了我认为可能会自动重试这两个异常的方法?但似乎不是。

所以我猜有两个问题:

  1. 我们可以在每个作业中手动救援Resque::TermException,并使用它来重新安排作业。但是有没有一种干净的方法可以为所有工作做到这一点?甚至是猴子补丁。
  2. resque-retry 不应该自动重试这些吗?你能想出什么理由不这样做吗?

谢谢!

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

4

4 回答 4

6

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

Heroku 在发布 a 后给予工人 30 秒的时间优雅地关闭SIGTERM。在大多数情况下,这是足够的时间来完成作业,如果作业无法完成,则剩余一些缓冲时间可以将作业重新排队到 Resque。但是,要使用所有这些时间,您需要设置RESQUE_PRE_SHUTDOWN_TIMEOUTRESQUE_TERM_TIMEOUT环境变量以及修补 Resque 以正确响应SIGTERM被发送到分叉进程。

这是一个修补 resque 并更详细地解释此问题的 gem:

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

于 2017-08-29T15:59:49.600 回答
1

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

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

于 2013-04-01T16:32:05.367 回答
1
  1. 我们可以在每个作业中手动从 Resque::TermException 中救援,并使用它来重新安排作业。但是有没有一种干净的方法可以为所有工作做到这一点?甚至是猴子补丁。

Resque::DirtyExit作业被SIGTERM信号终止时引发异常。正如您可以在此处阅读的那样,该作业没有机会捕获异常。

  1. resque-retry 不应该自动重试这些吗?你能想出什么理由不这样做吗?

不明白为什么不应该,调度程序是否正在运行?如果没有rake resque:scheduler

我针对我最近遇到的一些问题写了一篇详细的博文Resque::DirtyExit,也许有用 =>了解 Resque 内部结构 – Resque::DirtyExit 揭晓

于 2015-03-30T18:04:28.863 回答
1

我也为此苦苦挣扎了一段时间,但没有找到可靠的解决方案。

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

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

这个解决方案显然不是最理想的,但迄今为止,它是我找到的重试这些工作的最佳解决方案。

于 2015-08-15T11:52:11.547 回答