diff --git a/lib/crono/cli.rb b/lib/crono/cli.rb index d9944a7..01de7c7 100644 --- a/lib/crono/cli.rb +++ b/lib/crono/cli.rb @@ -79,9 +79,10 @@ module Crono end def start_working_loop - while (job = Crono.scheduler.next) - sleep(job.next - Time.now) - job.perform + while true + next_time, jobs = Crono.scheduler.next_jobs + sleep(next_time - Time.now) + jobs.each(&:perform) end end diff --git a/lib/crono/job.rb b/lib/crono/job.rb index 1245266..24a7922 100644 --- a/lib/crono/job.rb +++ b/lib/crono/job.rb @@ -17,8 +17,7 @@ module Crono end def next - next_time = period.next(since: last_performed_at) - next_time.past? ? period.next : next_time + period.next(since: last_performed_at) end def description diff --git a/lib/crono/scheduler.rb b/lib/crono/scheduler.rb index 284683b..f4088d9 100644 --- a/lib/crono/scheduler.rb +++ b/lib/crono/scheduler.rb @@ -12,14 +12,8 @@ module Crono jobs << job end - def next - queue.first - end - - private - - def queue - jobs.sort_by(&:next) + def next_jobs + jobs.group_by(&:next).sort_by {|time,_| time }.first end end diff --git a/spec/job_spec.rb b/spec/job_spec.rb index 9ea5fe5..6eb8c45 100644 --- a/spec/job_spec.rb +++ b/spec/job_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Crono::Job do - let(:period) { Crono::Period.new(2.day) } + let(:period) { Crono::Period.new(2.day, at: '15:00') } let(:job) { Crono::Job.new(TestJob, period) } let(:failing_job) { Crono::Job.new(TestFailingJob, period) } @@ -10,6 +10,12 @@ describe Crono::Job do expect(job.period).to be period end + describe '#next' do + it 'should return next performing time according to period' do + expect(job.next).to be_eql period.next + end + end + describe '#perform' do after { job.send(:model).destroy } @@ -47,7 +53,7 @@ describe Crono::Job do describe '#description' do it 'should return job identificator' do - expect(job.description).to be_eql('Perform TestJob every 2 days') + expect(job.description).to be_eql('Perform TestJob every 2 days at 15:00') end end diff --git a/spec/scheduler_spec.rb b/spec/scheduler_spec.rb index 7fddd4b..43748b6 100644 --- a/spec/scheduler_spec.rb +++ b/spec/scheduler_spec.rb @@ -1,27 +1,38 @@ require 'spec_helper' describe Crono::Scheduler do - before(:each) do - @scheduler = Crono::Scheduler.new - @jobs = [ - Crono::Period.new(3.day, at: 10.minutes.from_now.strftime('%H:%M')), - Crono::Period.new(1.day, at: 20.minutes.from_now.strftime('%H:%M')), - Crono::Period.new(7.day, at: 40.minutes.from_now.strftime('%H:%M')) - ].map { |period| Crono::Job.new(TestJob, period) } - @scheduler.jobs = @jobs - end + let(:scheduler) { Crono::Scheduler.new } describe '#add_job' do it 'should call Job#load on Job' do @job = Crono::Job.new(TestJob, Crono::Period.new(10.day, at: '04:05')) expect(@job).to receive(:load) - @scheduler.add_job(@job) + scheduler.add_job(@job) end end - describe '#next' do + describe '#next_jobs' do it 'should return next job in schedule' do - expect(@scheduler.next).to be @jobs[0] + scheduler.jobs = jobs = [ + Crono::Period.new(3.days, at: 10.minutes.from_now.strftime('%H:%M')), + Crono::Period.new(1.day, at: 20.minutes.from_now.strftime('%H:%M')), + Crono::Period.new(7.days, at: 40.minutes.from_now.strftime('%H:%M')) + ].map { |period| Crono::Job.new(TestJob, period) } + + time, jobs = scheduler.next_jobs + expect(jobs).to be_eql [jobs[0]] + end + + it 'should return an array of jobs scheduled at same time' do + time = 5.minutes.from_now + scheduler.jobs = jobs = [ + Crono::Period.new(1.day, at: time.strftime('%H:%M')), + Crono::Period.new(1.day, at: time.strftime('%H:%M')), + Crono::Period.new(1.day, at: 10.minutes.from_now.strftime('%H:%M')) + ].map { |period| Crono::Job.new(TestJob, period) } + + time, jobs = scheduler.next_jobs + expect(jobs).to be_eql [jobs[0], jobs[1]] end end end