Как составить расписание заданий Sidekiq в соответствии с повторяющимся расписанием в базе данных?

Я создал систему, в которой MeasurementS запускаются на основе MeasurementSettings. Каждый параметр определяет расписание, используя 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 вечера
  • MeasurementSetting с ID 2, с почасовым расписанием в каждый полный час (12:00, 01:00 и т. д.)

Теперь мне нужно:

  • Создать Measurement который использует настройку 1, каждый день в 12:00
  • Создать Measurement который использует настройку 2, каждый полный час
  • Позвоните работнику для этих измерений

Но как?

Должен ли я проверять, скажем каждую минуту, есть ли MeasurementSetting что определено произойти сейчас, а затем создать пустое Measurement записи, а затем запустить их с определенной настройкой с помощью Sidekiq?

Или я должен генерировать пустой Measurement записи с их настройками заранее, а расписание их таким образом?

Какой самый простой способ добиться этого?

2 ответа

Решение

Вот как я успешно это сделал:

  • Обновите вашу модель, которая должна работать по расписанию, с полем 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
    
  • Если это так, то проверьте, можем ли мы выполнить измерение, посмотрев в базу данных, нет ли предыдущих измерений с таким же запланированным временем начала. Итак, во-первых, мы должны получить запланированное время начала текущего расписания, например, когда сейчас 15:04. запланированное время начала могло быть 3:00 вечера.

    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
    

Я бы использовал cron каждую минуту, чтобы искать MeasurementSettings, которые должны запускаться СЕЙЧАС. Если да, создайте задание Sidekiq для немедленного запуска, которое заполняет измерение.

Другие вопросы по тегам