有没有办法在 Sidekiq 在工作中重新启动之前编写 运行 代码?

Is there way to run code before Sidekiq is restarted in the middle of a job?

我有一个 Sidekiq 作业,每 4 分钟 运行s。

此作业在再次执行代码之前检查当前代码块是否正在执行

process = ProcessTime.where("name = 'ad_queue_process'").first

# Return if job is running
return if process.is_running == true

如果 Sidekiq 在代码块中途重启,更新作业状态的代码永远不会 运行s

# Done running, update the process times and allow it to be ran again
process.update_attributes(is_running: false, last_execution_time: Time.now)

这导致作业永远不会 运行ning 除非我 运行 更新语句设置 is_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,在我们的讨论(下面的评论)之后,ensure 块(由分叉的工作线程执行)只能 运行 一些 ungua运行teed 毫秒前主线程强行终止这些工作线程,以便主线程做一些“清理”异常堆栈,以避免被 Heroku 发出 SIGKILL。因此,请确保您的 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,然后单击“运行”

  • 换句话说,即使信号是 SIGTERM(正常关闭信号),也总是在 SignalException 上调用,但是 ONLY SIGKILL 上的 EXCEPT(强制无法挽救的关机)。您可以通过检查我的 repl code 来验证此行为,然后将 Process.kill('TERM', Process.pid) 更改为 Process.kill('KILL', Process.pid),然后再次单击“运行”(您会注意到 puts 不会被调用)

  • 看着Heroku docs,我引用:

    When Heroku is going to shut down a dyno (for a restart or a new deploy, etc.), it first sends a SIGTERM signal to the processes in the dyno.

    After Heroku sends SIGTERM to your application, it will wait a few seconds and then send SIGKILL to force it to shut down, even if it has not finished cleaning up. In this example, the ensure block does not get called at all, the program simply exits

    ... 这意味着 ensure 块将被调用,因为它是 SIGTERM 而不是 SIGKILL,除非关闭需要很长时间,这可能是由于(我能想到 ATM 的某些原因):

    • 您的 perform 代码(或堆栈中的任何 ruby 代码;甚至是 gems)中的某些东西也拯救了 SignalException,甚至拯救了根Exception class 因为 SignalExceptionException 的子 class)但需要很长时间清理(即清理 connections 到 DB 或一些东西,或者 I/O 挂起你的应用程序的东西)

    • 或者,您自己上面的 ensure 块需要很长时间。 I.E 在执行 process.update_attributes(...) 时,由于某种原因数据库临时挂起/网络延迟或超时,那么 update 可能根本不会成功!并且 运行 会超时,其中从我上面的引用中,在 SIGTERM 几秒钟后,应用程序将被 Heroku 发送 SIGKILL.[= 强制停止38=]

...这都意味着我的解决方案仍然不完全可靠,但在正常情况下应该可以工作