【发布时间】:2019-02-05 16:27:14
【问题描述】:
我有一个 Sidekiq 作业,每 4 分钟运行一次。
此作业在再次执行代码之前检查当前代码块是否正在执行
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 重启之前执行代码?
【问题讨论】:
-
如何重启 Sidekiq?它通常会“优雅地”停止/重新启动,这意味着它将在重新启动/停止之前首先完成所有正在运行的作业:reference 但是如果您在开发中使用 CTRL+C,是的,它会立即关闭,但这是在开发中。如果您想确保“更新”只会在没有错误的情况下提交到数据库中(即仅当 Sidekiq 在工作中间的 dev env 中不是 CTRL+C-ed 时),那么您可以将
ProcessTime.transaction do ... end块中的整个工作 -
旁注:这无论如何都是错误的方法,容易受到竞争条件的影响。应该使用消息队列在作业完成 后确认消息。另一个(低级别)选项是
Mutex/ConditionalVariable。所有其他解决方案迟早会导致竞争条件和两个作业同时并发执行。 -
@RickS 哦,我明白了,您在 Heroku 中使用 Sidekiq。以前没有在那里使用过,但我发现了它中途关闭的原因(可能你的工作需要超过 30 秒才能运行?)。从this doc,它说
"Keep in mind that Heroku puts a hard limit of 30 seconds on a process restart, the -t 25 tells Sidekiq to give the jobs 25 seconds to finish before starting the "force shutdown" procedure" -
@RickS 查看this,似乎 Heroku 向进程发送了“SIGTERM”(大概这也适用于 sidekiq 进程),因为它是“SIGTERM”而不是“SIGKILL” (无法挽回的强制关机),那么我想你仍然可以在你的
perform方法周围拯救它(ps未经测试),但你可以尝试:def perform; # code here...; rescue SignalException => e; ensure; process.update(...); end -
@RickS 虽然,在 Heroku 页面上进一步阅读:
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中执行update堵塞;仍然不是 100% 可靠,即更新时临时数据库超时
标签: ruby-on-rails ruby sidekiq