【问题标题】:Rufus-scheduler scheduling twice despite using locks尽管使用了锁,但 Rufus-scheduler 调度了两次
【发布时间】:2018-10-05 22:40:27
【问题描述】:

我很清楚为什么会发生这种情况(两个 ruby​​ 运行时),这对于以前没有阅读 RS 常见问题解答或在 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: trueMyOtherSidekiqWorker 的新实例仍会在一个仍在运行时被调用。

我一定遗漏了一些明显的东西,谢谢你的帮助。

【问题讨论】:

    标签: heroku rufus-scheduler


    【解决方案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 产生任何影响。

    您可以从https://github.com/jmettraux/rufus-scheduler#advanced-lock-schemes 获得灵感,为 rufus-scheduler 实现自定义锁定机制(可能通过数据库,因为它由您的 Ruby 进程共享),但这对overlap: falseblocking: true 没有帮助。

    如果您仍然想拥有overlap: falseblocking: true,您可以查看https://devcenter.heroku.com/articles/scheduled-jobs-custom-clock-processes 并使用 rufus-scheduler 或 Clockwork 在专用进程/dyno 中进行调度,并且不需要调度锁。

    我的其余答案是关于你的代码,而不是关于你正在经历的双重调度。

    scheduler.down?

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

    为什么你有这个unless b_scheduler.down? 如果b_scheduler 已经关闭,则该块根本不会被执行。

    这就足够了:

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

    a_scheduler 与 b_scheduler

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

    require 'rufus-scheduler'                                                   
    
    #scheduler = Rufus::Scheduler.new(lockfile: '.rufus-scheduler.lock')     
    scheduler = Rufus::Scheduler.new                                  
    
    unless defined?(Rails::Console) || File.split($0).last == 'rake' || !Rails.env.production?                                                                  
      scheduler.cron '0 21 * * *', overlap: false, blocking: true do            
        MySidekiqWorker.perform_async                                           
      end                                                                       
      scheduler.every '1h', overlap: false, blocking: true do                   
        MyOtherSidekiqWorker.perform_async                                      
      end                                                                       
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-06
      • 1970-01-01
      • 2021-06-25
      • 2016-01-10
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      相关资源
      最近更新 更多