如何根据数据库中的重复计划安排Sidekiq作业?

时间:2014-08-13 09:36:38

标签: ruby-on-rails scheduled-tasks sidekiq ice-cube

我已经建立了一个基于Measurement运行MeasurementSetting的系统。每个设置使用ice_cube(以及一些其他测量属性)定义计划。我能够为每个设置编辑此计划,然后使用以下内容轮询下一次出现:

def next_occurrences
  schedule.occurrences(Time.now + 1.day)
end

这给了我一组时间戳,应该有一个Measurement

现在,我也安装了Sidekiq,并且我可以使用MeasurementWorker在特定时间成功运行测量。为此,我只创建一个空的Measurement记录,将其与其设置相关联,然后perform_async(或perform_at(...))此工作人员:

class MeasurementWorker
  include Sidekiq::Worker
  sidekiq_options retry: 1, backtrace: true

  def perform(measurement_id)
    Measurement.find(measurement_id).run
  end
end

缺少的是我不知何故需要根据设置的时间表创建空测量。但是我该怎么做呢?

说我有以下数据:

  • MeasurementSetting,ID为1,每日时间安排在中午12:00
  • ID为2的
  • MeasurementSetting,每小时(上午12:00,上午01:00等)按小时计划。

现在我需要:

  • 创建一个Measurement,使用设置1,每天12点
  • 创建一个Measurement,每隔一小时使用设置2
  • 致电工人进行这些测量

但是怎么样?

我应该每分钟检查是否有MeasurementSetting被定义为 now ,然后创建空的Measurement记录,然后运行它们使用Sidekiq的具体设置?

或者我应该提前使用他们的设置生成空Measurement条记录,并以这种方式安排它们?

实现这一目标的最简单方法是什么?

2 个答案:

答案 0 :(得分:0)

我会每分钟使用cron来寻找应该立即运行的MeasurementSettings。如果是,请创建一个Sidekiq作业立即运行,填充测量值。

答案 1 :(得分:0)

以下是我成功完成的方式:

  • 使用字段planned_start_time更新应按计划运行的模型。这将保留计划开始的时间。

  • 使用whenever Gem每分钟运行一次类方法,例如Measurement.run_all_scheduled

  • 在该方法中,浏览每个设置(即时间表的位置),并检查它是否正在发生:

    setting = MeasurementSetting.find(1) # get some setting, choose whatever
    schedule = setting.schedule
    if not schedule.occurring_at? Time.now
      # skip this measurement, since it's not planned to run now
    
  • 如果是这种情况,那么检查我们是否可以通过查看数据库来运行测量,如果没有任何先前的测量具有相同的计划开始时间。首先,我们必须获得当前时间表的计划开始时间,例如现在是3点04分。计划的开始时间可能是下午3点。

    this_planned_start_time = schedule.previous_occurrence(Time.now).start_time
    

    然后我们检查最后一次测量的开始时间(limit(1)是否只是最后一次)是否相同。

    if Measurement.limit(1).last.planned_start_time != this_planned_start_time
      # skip this one, since it was already run
    
  • 如果没有,我们可以继续设置测量值。

    measurement = Measurement.create measurement_setting: setting, 
                                     planed_start_time: this_planned_start_time
    
  • 然后运行它:

    measurement.delay.run