From e22f1ae1868f4d636a9f6440d0385c35da8745b8 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 14 Mar 2014 13:02:21 -0400 Subject: [PATCH] Support for a daily job at a certain hour. Convert backup job to run at 3am instead of randomly during the day. --- app/jobs/scheduled/create_backup.rb | 2 +- lib/scheduler/schedule.rb | 10 +- lib/scheduler/schedule_info.rb | 44 ++++++- .../scheduler/schedule_info_spec.rb | 108 +++++++++++++----- 4 files changed, 125 insertions(+), 39 deletions(-) diff --git a/app/jobs/scheduled/create_backup.rb b/app/jobs/scheduled/create_backup.rb index 00de7a6df94..7e47dadc207 100644 --- a/app/jobs/scheduled/create_backup.rb +++ b/app/jobs/scheduled/create_backup.rb @@ -2,7 +2,7 @@ require_dependency "backup_restore" module Jobs class CreateBackup < Jobs::Scheduled - every 1.day + daily at: 3.hours sidekiq_options retry: false def execute(args) diff --git a/lib/scheduler/schedule.rb b/lib/scheduler/schedule.rb index 10a7f92977d..822e06fa37a 100644 --- a/lib/scheduler/schedule.rb +++ b/lib/scheduler/schedule.rb @@ -1,4 +1,12 @@ module Scheduler::Schedule + + def daily(options=nil) + if options + @daily = options + end + @daily + end + def every(duration=nil) if duration @every = duration @@ -15,6 +23,6 @@ module Scheduler::Schedule end def scheduled? - !!@every + !!@every || !!@daily end end diff --git a/lib/scheduler/schedule_info.rb b/lib/scheduler/schedule_info.rb index 18d12147be9..7a79463a02c 100644 --- a/lib/scheduler/schedule_info.rb +++ b/lib/scheduler/schedule_info.rb @@ -31,14 +31,22 @@ module Scheduler def valid? return false unless @next_run - (!@prev_run && @next_run < Time.now.to_i + 5.minutes) || - ( @prev_run && - @prev_run <= Time.now.to_i && - @next_run < @prev_run + @klass.every * (1 + @manager.random_ratio) - ) + (!@prev_run && @next_run < Time.now.to_i + 5.minutes) || valid_every? || valid_daily? end - def schedule! + def valid_every? + return false unless @klass.every + @prev_run && + @prev_run <= Time.now.to_i && + @next_run < @prev_run + @klass.every * (1 + @manager.random_ratio) + end + + def valid_daily? + return false unless @klass.daily + @prev_run && @prev_run <= Time.now.to_i && @next_run < @prev_run + 1.day + end + + def schedule_every! if !valid? && @prev_run mixup = @klass.every * @manager.random_ratio mixup = (mixup * Random.rand - mixup / 2).to_i @@ -48,6 +56,30 @@ module Scheduler if !valid? @next_run = Time.now.to_i + 5.minutes * Random.rand end + end + + def schedule_daily! + return if valid? + + at = @klass.daily[:at] || 0 + today_begin = Time.now.midnight.to_i + today_offset = DateTime.now.seconds_since_midnight + + # If it's later today + if at > today_offset + @next_run = today_begin + at + else + # Otherwise do it tomorrow + @next_run = today_begin + 1.day + at + end + end + + def schedule! + if @klass.every + schedule_every! + elsif @klass.daily + schedule_daily! + end write! end diff --git a/spec/components/scheduler/schedule_info_spec.rb b/spec/components/scheduler/schedule_info_spec.rb index db3234afad5..fa5baec4914 100644 --- a/spec/components/scheduler/schedule_info_spec.rb +++ b/spec/components/scheduler/schedule_info_spec.rb @@ -4,48 +4,94 @@ require 'scheduler/scheduler' describe Scheduler::ScheduleInfo do - class RandomJob - extend ::Scheduler::Schedule + let(:manager){ Scheduler::Manager.new } - every 1.hour + context "every" do + class RandomJob + extend ::Scheduler::Schedule - def perform - # work_it + every 1.hour + + def perform + # work_it + end + end + + before do + @info = manager.schedule_info(RandomJob) + @info.del! + $redis.del manager.class.queue_key + end + + after do + manager.stop! + end + + it "is a scheduled job" do + RandomJob.should be_scheduled + end + + it 'starts off invalid' do + @info.valid?.should be_false + end + + it 'will have a due date in the next 5 minutes if it was blank' do + @info.schedule! + @info.valid?.should be_true + @info.next_run.should be_within(5.minutes).of(Time.now.to_i) + end + + it 'will have a due date within the next hour if it just ran' do + @info.prev_run = Time.now.to_i + @info.schedule! + @info.valid?.should be_true + @info.next_run.should be_within(1.hour * manager.random_ratio).of(Time.now.to_i + 1.hour) + end + + it 'is invalid if way in the future' do + @info.next_run = Time.now.to_i + 1.year + @info.valid?.should be_false end end - let(:manager){ Scheduler::Manager.new } + context "daily" do - before do - @info = manager.schedule_info(RandomJob) - @info.del! - $redis.del manager.class.queue_key - end + class DailyJob + extend ::Scheduler::Schedule + daily at: 2.hours - after do - manager.stop! - end + def perform + end + end - it 'starts off invalid' do - @info.valid?.should be_false - end + before do + @info = manager.schedule_info(DailyJob) + @info.del! + $redis.del manager.class.queue_key + end - it 'will have a due date in the next 5 minutes if it was blank' do - @info.schedule! - @info.valid?.should be_true - @info.next_run.should be_within(5.minutes).of(Time.now.to_i) - end + after do + manager.stop! + end - it 'will have a due date within the next hour if it just ran' do - @info.prev_run = Time.now.to_i - @info.schedule! - @info.valid?.should be_true - @info.next_run.should be_within(1.hour * manager.random_ratio).of(Time.now.to_i + 1.hour) - end + it "is a scheduled job" do + DailyJob.should be_scheduled + end - it 'is invalid if way in the future' do - @info.next_run = Time.now.to_i + 1.year - @info.valid?.should be_false + it "starts off invalid" do + @info.valid?.should be_false + end + + it "will have a due date at the appropriate time if blank" do + @info.next_run.should be_nil + @info.schedule! + @info.valid?.should be_true + end + + it 'is invalid if way in the future' do + @info.next_run = Time.now.to_i + 1.year + @info.valid?.should be_false + end end end