Ruby on rails 在工作中间重新启动SIDKIQ之前是否有运行代码的方法?
我有一个每4分钟运行一次的Sidekiq作业 此作业在再次执行代码之前检查当前代码块是否正在执行Ruby on rails 在工作中间重新启动SIDKIQ之前是否有运行代码的方法?,ruby-on-rails,ruby,sidekiq,Ruby On Rails,Ruby,Sidekiq,我有一个每4分钟运行一次的Sidekiq作业 此作业在再次执行代码之前检查当前代码块是否正在执行 process = ProcessTime.where("name = 'ad_queue_process'").first # Return if job is running return if process.is_running == true 如果Sidekiq在代码块的中途重新启动,则更新作业状态的代码永远不会运行 # Done running, update the process
process = ProcessTime.where("name = 'ad_queue_process'").first
# Return if job is running
return if process.is_running == true
如果Sidekiq在代码块的中途重新启动,则更新作业状态的代码永远不会运行
# Done running, update the process times and allow it to be ran again
process.update_attributes(is_running: false, last_execution_time: Time.now)
这导致作业永远不会运行,除非我运行update语句来设置is\u running=false
在重启Sidekiq之前,有没有办法执行代码?处理Sidekiq关机异常
class SomeWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(params)
...
rescue Sidekiq::Shutdown
SomeWorker.perform_async(params)
end
end
更新:
- 感谢@Aaron,在我们的讨论(下面的评论)之后,
块(由分叉的工作线程执行)只能在主线程强制终止这些工作线程之前运行几毫秒,以便主线程对异常堆栈进行一些“清理”,为了避免被希罗库杀死。因此,请确保您的sure
确保
代码应该非常快李>
def perform(*args)
# your code here
ensure
process.update_attributes(is_running: false, last_execution_time: Time.now)
end
- 无论方法是“成功”还是引发异常,都始终调用上面的
确保
。我测试了这个:看到这个,点击“运行”
- 换句话说,即使信号是
(正常关机信号),也总是在SIGTERM
上调用此函数,但仅在SignalException
上调用(强制不可提示关机)。您可以通过检查my来验证此行为,然后将SIGKILL
更改为Process.kill('TERM',Process.pid)
,然后再次单击“run”(您会注意到不会调用Process.kill('kill',Process.pid)
)put
- 看一看,我引述:
当Heroku要关闭dyno(重新启动或新部署等)时,它首先向dyno中的进程发送SIGTERM信号
Heroku向您的应用程序发送SIGTERM后,它将等待几秒钟,然后发送SIGKILL以强制其关闭,即使它尚未完成清理。在本例中,确保块根本没有被调用,程序只是退出
。。。这意味着
块将被调用,因为它是sure
而不是SIGTERM
,除非关闭需要很长时间,这可能是由于(我认为是ATM的某些原因):SIGKILL
- 您的
执行
代码(或堆栈中的任何ruby代码;甚至gems)中的某些操作,这些操作也拯救了
,甚至拯救了根SignalException
类,因为Exception
是SignalException
的子类,但需要很长时间才能清理(即清理连接到DB或其他东西的Exception
连接,或挂起应用程序的i/O内容)
- 或者,您自己的
确保上面的
块花费很长时间。例如,在执行
,由于某种原因,DB临时挂起/网络延迟或超时,那么,过程时。更新\u属性(…)
可能根本不会成功!并且将耗尽时间,从我上面的引文中可以看出,在更新
之后几秒钟,Heroku发送一个SIGTERM
,应用程序将被迫停止SIGKILL
- 您的
…这一切都意味着我的解决方案仍然不完全可靠,但在正常情况下应该可以工作您如何重新启动Sidekiq?它通常“优雅地”停止/重新启动这意味着它将在重新启动/停止之前完成所有运行的任务:但是如果您在开发中使用CTRL+C,是的,它将立即关闭,但这是在开发中。如果您想确保“更新”只在没有错误的情况下在DB中提交(也就是说,只有当Sidekiq在任务中间没有CTRL+C-ED在DEV Env中)时才可以完成。,然后您可以将整个作业包装在一个
ProcessTime.transaction do…end
blockside注意:这在任何情况下都是错误的方法,容易受到竞争条件的影响。一个应在作业完成后使用消息队列确认消息。另一个(低级别)选项是一个Mutex
/ConditionalVariable
。所有其他解决方案迟早会导致竞争条件和同时执行两个作业。@RickS哦,我知道了,你在Heroku中使用了Sidekiq。以前没有在那里使用过,但我发现了它中途关闭的原因(可能您的作业运行时间超过30秒?)。从中,它说,“请记住,Heroku对进程重启设置了30秒的硬限制,-t25告诉Sidekiq在开始“强制关机”过程之前,给作业25秒的时间来完成”
@RickS看着,似乎Heroku向进程发送了一个“SIGTERM”(这可能也适用于sidekiq过程),因为它是一个“SIGTERM”而不是“SIGKILL”(不可提示的强制关机),那么我猜您仍然可以围绕perform
方法(p.s.未测试)来拯救它,但您可以尝试:def perform;#这里的代码…;rescue SignalException=>e;sure;process.update(…);end
@RickS尽管如此,请进一步阅读Heroku页面:在Heroku向您的应用程序发送SIGTERM后,它将等待几秒钟,然后发送SIGKILL以强制关闭,即使它尚未完成清理。在本例中,确保块根本没有被调用,程序只会退出:
。因此,如果您的作业“挂起”/需要很长时间才能关闭,然后我的“rescue;SECURE”解决方案仍然不完全可靠,但希望不会花太长时间,因为您只是在SECURE
块中执行更新
;仍然不是100%可靠,即更新时的临时DB超时,根据该指南所述“回滚db事务时需要这样做,否则Ruby的线程#kill将提交……不要在工作中挽救此错误