ruby-on-rails - 有没有办法在 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 times and allow it to be ran again
process.update_attributes(is_running: false, last_execution_time: Time.now)

这导致作业永远不会运行,除非我运行更新语句来设置 is_running = false

有什么办法可以在Sidekiq重启之前执行代码吗?

最佳答案

更新:

  • 感谢@Aaron,并根据我们的讨论(下面的评论),ensure block (由 fork 的工作线程执行)只能在主线程之前运行几毫秒-thread 强行终止这些工作线程,以便主线程对异常堆栈进行一些“清理”,以避免被 Heroku 发出 SIGKILL。因此,请确保您的 ensure 代码应该非常快!

长话短说:

def perform(*args)
  # your code here
ensure
  process.update_attributes(is_running: false, last_execution_time: Time.now)
end
  • 无论方法“成功”还是引发异常,上面的 ensure 总是被调用。我测试了这个:看这个 repl code , 然后点击“运行”

  • 换句话说,即使在 SignalException 上,即使信号是 SIGTERM(正常关闭信号),也总是会调用它,但 ONLY EXCEPTSIGKILL 上(强制无法挽救的关机)。您可以通过检查我的 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 block ,因为它是 SIGTERM 而不是 SIGKILL,除非关闭down 需要很长时间,这可能是由于(我能想到 ATM 的一些原因):

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

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

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

关于ruby-on-rails - 有没有办法在 Sidekiq 在工作中重新启动之前运行代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54538852/

相关文章:

ruby - capybara 点击方法不适用于 selenium webdriver

ruby - 如何在纯 Ruby 中按 DateTime 的日期数组分组?

ruby-on-rails - Redis 引发 "NOAUTH Authentication required"错误但没有密码设置

ruby-on-rails - 如何配置sidekiq队列一次只运行任务

ruby-on-rails - Rails 服务器 (Puma) : SSL not available in this build (StandardError)

javascript - 禁用基于 Rails 中另一个字段的字段表单

mysql - 带有 MySQL 的 Ruby 服务器

ruby-on-rails - ActiveJob 在生产环境中没有使用 sidekiq

ruby-on-rails - Capybara 特性测试不提交数据库事务

ruby-on-rails - CakePHP 是否以 Ruby on Rails 为模型?