我有一个每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 times and allow it to be ran again
process.update_attributes(is_running: false, last_execution_time: Time.now)
除非我运行更新语句来设置is_running = false
,否则这导致Job永远不会运行
在Sidekiq重启之前有没有办法执行代码?
ensure
块(由分叉的工作线程执行)只能在主线程强制终止这些工作线程之前运行几个毫无保证的毫秒,命令主线程做一些“清理”异常堆栈,以避免由Heroku获取SIGKILL-ed。因此,请确保您的ensure
代码真的很快!TL; DR:
def perform(*args)
# your code here
ensure
process.update_attributes(is_running: false, last_execution_time: Time.now)
end
ensure
。我测试了这个:看到这个repl code,然后点击“运行”SignalException
上也会调用它,即使信号是SIGTERM
(正常关闭信号),但仅限于SIGKILL
(强制不可撤销关机)。您可以通过检查我的repl code验证此行为,然后将Process.kill('TERM', Process.pid)
更改为Process.kill('KILL', Process.pid)
,然后再次单击“运行”(您将注意到不会调用puts
)ensure
区块将被调用,因为它是SIGTERM
而不是SIGKILL
,只是因为关闭需要一段时间,这可能是由于(某些原因我可以想到ATM):
你的perform
代码里面的东西(或堆栈中的任何红宝石代码;甚至宝石)也拯救了SignalException
,甚至拯救了根Exception
类,因为SignalException
是Exception
的子类)但需要很长时间清理(即清理connections
)到DB或其他东西,或挂起你的应用程序的I / O东西)
或者,你自己的ensure
块上面需要一个懒散的时间。 I.E当做process.update_attributes(...)
时,由于某种原因数据库临时挂起/网络延迟或超时,那么update
可能根本不会成功!并且将耗尽时间,从我上面的引用,在SIGTERM
几秒后,申请将被迫由Heroku发送SIGKILL
停止。...这一切都意味着我的解决方案仍然不完全可靠,但应该在正常情况下工作
处理sidekiq关闭异常
class SomeWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(params)
...
rescue Sidekiq::Shutdown
SomeWorker.perform_async(params)
end
end