TLDR:
把它放在你的工作方法的顶部:
begin
term_now = false
old_term_handler = trap 'TERM' do
term_now = true
old_term_handler.call
end
和
确保至少每十秒调用一次:
if term_now
puts 'told to terminate'
return true
end
和
在你的方法的最后,把这个:
ensure
trap 'TERM', old_term_handler
end
解释:
我遇到了同样的问题,并遇到了这篇 Heroku 文章。
该作业包含一个外部循环,因此我按照文章添加了一个trap('TERM')
and exit
。但是delayed_job
,将其捡起failed with SystemExit
并将任务标记为失败。
现在SIGTERM
被我们trap
的工人处理程序困住了,它不会被调用,而是立即重新启动作业,然后在SIGKILL
几秒钟后得到。回到原点。
我尝试了一些替代方案exit
:
我的最终解决方案是我的答案顶部给出的解决方案,它包括三个部分:
在我们开始可能很长的工作之前,我们'TERM'
通过执行 a trap
(如 Heroku 文章中所述)添加一个新的中断处理程序,并使用它来设置term_now = true
.
但我们还必须抓住old_term_handler
哪个延迟作业工人代码集(由 返回trap
)并记住call
它。
我们仍然必须确保我们Delayed:Job:Worker
有足够的时间将控制权返回给它,以便它清理和关闭,所以我们应该term_now
至少(略低于)每十秒检查一次,return
如果它是true
。
您可以return true
或return false
取决于您是否希望该工作被认为是成功的。
最后,重要的是要记住删除处理程序并Delayed:Job:Worker
在完成后重新安装处理程序。如果你没有这样做,你将保留一个对我们添加的引用的悬空引用,如果你在其上添加另一个引用,这可能会导致内存泄漏(例如,当工作人员再次开始这项工作时)。