是否有办法在Sidekiq在作业中重新启动之前运行代码?

问题描述 投票:2回答:2

我有一个每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重启之前有没有办法执行代码?

ruby-on-rails ruby sidekiq
2个回答
3
投票

更新:

  • 感谢@Aaron,并按照我们的讨论(下面的评论),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
  • 看看Heroku docs,我引用: 当Heroku要关闭dyno(重启或新部署等)时,它首先会向dyno中的进程发送SIGTERM信号。 在Heroku将SIGTERM发送到您的应用程序之后,它将等待几秒钟然后发送SIGKILL以强制它关闭,即使它还没有完成清理。在这个例子中,完全不会调用ensure块,程序只是退出 ...这意味着ensure区块将被调用,因为它是SIGTERM而不是SIGKILL,只是因为关闭需要一段时间,这可能是由于(某些原因我可以想到ATM): 你的perform代码里面的东西(或堆栈中的任何红宝石代码;甚至宝石)也拯救了SignalException,甚至拯救了根Exception类,因为SignalExceptionException的子类)但需要很长时间清理(即清理connections)到DB或其他东西,或挂起你的应用程序的I / O东西) 或者,你自己的ensure块上面需要一个懒散的时间。 I.E当做process.update_attributes(...)时,由于某种原因数据库临时挂起/网络延迟或超时,那么update可能根本不会成功!并且将耗尽时间,从我上面的引用,在SIGTERM几秒后,申请将被迫由Heroku发送SIGKILL停止。

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


0
投票

处理sidekiq关闭异常

class SomeWorker
  include Sidekiq::Worker

  sidekiq_options queue: :default

  def perform(params)
    ...

  rescue Sidekiq::Shutdown
    SomeWorker.perform_async(params)
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.