Rufus-Scheduler两次调度,尽管使用了锁

时间:2018-10-05 05:48:57

标签: heroku rufus-scheduler

我很清楚为什么会发生这种情况(两个ruby运行时),对于那些以前没有阅读过RS FAQ或在SO上进行过搜索的人来说,这是一个常见问题,但是我花了几天的时间尝试许多规定的解决方案,但我的rufus-scheduler继续调用两次。

这仅发生在在Heroku上运行Rails 5.0.6,Puma服务器的生产环境中。

这是我的scheduler.rb:

require 'rufus-scheduler'

a_scheduler = Rufus::Scheduler.new(:lockfile => ".rufus-scheduler-a.lock")
b_scheduler = Rufus::Scheduler.new(:lockfile => ".rufus-scheduler-b.lock")

unless defined?(Rails::Console) || File.split($0).last == 'rake' || !Rails.env.production?
  a_scheduler.cron '0 21 * * *', overlap: false, blocking: true do
    MySidekiqWorker.perform_async unless a_scheduler.down? 
  end

  b_scheduler.every '1h', overlap: false, blocking: true do
    MyOtherSidekiqWorker.perform_async unless b_scheduler.down?
  end
end

我尝试了锁定文件,配置了自己的scheduler_lock,为.every.cron使用了不同的参数。而且,即使我有overlap: falseblocking: true,似乎MyOtherSidekiqWorker的新实例仍会在运行时被调用。

我肯定想念一些明显的东西,谢谢您的帮助。

1 个答案:

答案 0 :(得分:1)

所以Heroku dynos not sharing the file system

在dyno d0上看到的.rufus-scheduler-a.lock不是在dyno d1上看到的.rufus-scheduler-a.lock

您的Heroku dynos不共享相同的文件系统,并且它们也不共享相同的Ruby进程,因此也不是相同的rufus-scheduler实例。因此overlap: falseblocking: true从dyno d0到dyno d1不会有任何影响。

您可以为rufus-scheduler实现自定义锁定机制,以从https://github.com/jmettraux/rufus-scheduler#advanced-lock-schemes中汲取灵感(可能是通过数据库,因为它已由Ruby进程共享),但这对overlap: false和{{1 }}。

如果您仍然希望拥有blocking: trueoverlap: false,则可以查看https://devcenter.heroku.com/articles/scheduled-jobs-custom-clock-processes并使用rufus-scheduler或Clockwork在专用的进程/ dyno中进行调度,而没有需要计划锁定。

我剩下的答案是关于您的代码的,而不是关于您正在经历的双重计划。

scheduler.down?

blocking: true

如果b_scheduler.every '1h', overlap: false, blocking: true do MyOtherSidekiqWorker.perform_async unless b_scheduler.down? end 降下,为什么会有这个unless b_scheduler.down?呢?根本不会执行该块。

这就足够了:

b_scheduler

a_scheduler与b_scheduler

您不需要为每个作业使用一个调度程序。您可以简单地写:

b_scheduler.every '1h', overlap: false, blocking: true do
  MyOtherSidekiqWorker.perform_async
end