Как составить расписание заданий Sidekiq в соответствии с повторяющимся расписанием в базе данных?
Я создал систему, в которой Measurement
S запускаются на основе MeasurementSetting
s. Каждый параметр определяет расписание, используя 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 для немедленного запуска, которое заполняет измерение.