class Kuroko2::JobSchedule
def self.launch_scheduled_jobs!(time_from, time_to)
def self.launch_scheduled_jobs!(time_from, time_to) includes(job_definition: :job_suspend_schedules).find_each do |schedule| definition = schedule.job_definition suspend_times = schedule.suspend_times(time_from, time_to) schedule.scheduled_times(time_from, time_to).each do |time| if definition.suspended? Kuroko2.logger.info("Skipped suspended \"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`") elsif suspend_times.include?(time) Kuroko2.logger.info("Skipped schedule suspended \"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`") else launched_by = "\"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`" definition.create_instance(launched_by: launched_by) end end end end
def has_suspend_schedules?
def has_suspend_schedules? job_definition && !job_definition.job_suspend_schedules.empty? end
def next(now = Time.current)
def next(now = Time.current) return if suspended_all? next_time = Chrono::Iterator.new(self.cron, now: now).next suspend_times = suspend_times(next_time, next_time) if suspend_times.include?(next_time) self.next(next_time) else next_time end end
def scheduled_times(time_from, time_to)
def scheduled_times(time_from, time_to) it = Chrono::Iterator.new(cron, now: time_from) scheduled_times = [] loop do next_time = it.next if next_time <= time_to scheduled_times << next_time else break end end scheduled_times.map(&:in_time_zone) end
def suspend_times(time_from, time_to)
def suspend_times(time_from, time_to) if has_suspend_schedules? job_definition.job_suspend_schedules. map { |schedule| schedule.suspend_times(time_from, time_to) }.flatten.uniq else [] end end
def suspended_all?
def suspended_all? return false unless has_suspend_schedules? launch_schedule = Chrono::Schedule.new(cron) schedule = CHRONO_SCHEDULE_METHODS.each_with_object({}) do |method, h| h[method] = launch_schedule.public_send(method) end job_definition.job_suspend_schedules.each do |suspend_schedule_model| suspend_schedule = Chrono::Schedule.new(suspend_schedule_model.cron) CHRONO_SCHEDULE_METHODS.each do |method| schedule[method] -= suspend_schedule.public_send(method) end # https://linux.die.net/man/5/crontab # > Note: The day of a command's execution can be specified by two fields # > day of month, and day of week. If both fields are restricted (ie, aren't *), # > the command will be run when either field matches the current time. # > For example, "30 4 1,15 * 5" would cause a command to be run at 4:30 am # > on the 1st and 15th of each month, plus every Friday. if suspend_schedule.wdays? && suspend_schedule.days? case when launch_schedule.wdays? && !launch_schedule.days? schedule[:days] = [] when !launch_schedule.wdays? && launch_schedule.days? schedule[:wdays] = [] end end end schedule.values.all?(&:empty?) end
def validate_cron_schedule
def validate_cron_schedule if CRON_FORMAT === cron self.next end nil rescue Chrono::Fields::Base::InvalidField => e errors.add(:cron, "has invalid field: #{e.message}") end