From 250a244de5df9c0727c036f744079c29ac58973e Mon Sep 17 00:00:00 2001 From: Dominik Sander Date: Mon, 1 Sep 2014 00:41:53 +0200 Subject: [PATCH] Added specs for the HuginnScheduler --- lib/huginn_scheduler.rb | 105 +++++++++++++++--------------- spec/env.test | 1 + spec/lib/huginn_scheduler_spec.rb | 77 ++++++++++++++++++++++ 3 files changed, 130 insertions(+), 53 deletions(-) create mode 100644 spec/lib/huginn_scheduler_spec.rb diff --git a/lib/huginn_scheduler.rb b/lib/huginn_scheduler.rb index 3a300b2c..c342842a 100644 --- a/lib/huginn_scheduler.rb +++ b/lib/huginn_scheduler.rb @@ -1,16 +1,54 @@ require 'rufus/scheduler' class HuginnScheduler + FAILED_JOBS_TO_KEEP = 100 attr_accessor :mutex def initialize @rufus_scheduler = Rufus::Scheduler.new + self.mutex = Mutex.new end def stop @rufus_scheduler.stop end + def run! + tzinfo_friendly_timezone = ActiveSupport::TimeZone::MAPPING[ENV['TIMEZONE'].present? ? ENV['TIMEZONE'] : "Pacific Time (US & Canada)"] + + # Schedule event propagation. + @rufus_scheduler.every '1m' do + propagate! + end + + # Schedule event cleanup. + @rufus_scheduler.cron "0 0 * * * " + tzinfo_friendly_timezone do + cleanup_expired_events! + end + + # Schedule failed job cleanup. + @rufus_scheduler.every '1h' do + cleanup_failed_jobs! + end + + # Schedule repeating events. + %w[1m 2m 5m 10m 30m 1h 2h 5h 12h 1d 2d 7d].each do |schedule| + @rufus_scheduler.every schedule do + run_schedule "every_#{schedule}" + end + end + + # Schedule events for specific times. + 24.times do |hour| + @rufus_scheduler.cron "0 #{hour} * * * " + tzinfo_friendly_timezone do + run_schedule hour_to_schedule_name(hour) + end + end + + @rufus_scheduler.join + end + + private def run_schedule(time) with_mutex do puts "Queuing schedule for #{time}" @@ -33,10 +71,23 @@ class HuginnScheduler end def cleanup_failed_jobs! - first_to_delete = Delayed::Job.where.not(failed_at: nil).order("failed_at DESC").offset(ENV['FAILED_JOBS_TO_KEEP'].try(:to_i) || 100).limit(ENV['FAILED_JOBS_TO_KEEP'].try(:to_i) || 100).pluck(:failed_at).first + num_to_keep = (ENV['FAILED_JOBS_TO_KEEP'].presence || FAILED_JOBS_TO_KEEP).to_i + first_to_delete = Delayed::Job.where.not(failed_at: nil).order("failed_at DESC").offset(num_to_keep).limit(num_to_keep).pluck(:failed_at).first Delayed::Job.where(["failed_at <= ?", first_to_delete]).delete_all if first_to_delete.present? end + def hour_to_schedule_name(hour) + if hour == 0 + "midnight" + elsif hour < 12 + "#{hour}am" + elsif hour == 12 + "noon" + else + "#{hour - 12}pm" + end + end + def with_mutex ActiveRecord::Base.connection_pool.with_connection do mutex.synchronize do @@ -44,56 +95,4 @@ class HuginnScheduler end end end - - def run! - self.mutex = Mutex.new - - tzinfo_friendly_timezone = ActiveSupport::TimeZone::MAPPING[ENV['TIMEZONE'].present? ? ENV['TIMEZONE'] : "Pacific Time (US & Canada)"] - - # Schedule event propagation. - - @rufus_scheduler.every '1m' do - propagate! - end - - # Schedule event cleanup. - - @rufus_scheduler.cron "0 0 * * * " + tzinfo_friendly_timezone do - cleanup_expired_events! - end - - # Schedule failed job cleanup. - - @rufus_scheduler.every '1h' do - cleanup_failed_jobs! - end - - - # Schedule repeating events. - - %w[1m 2m 5m 10m 30m 1h 2h 5h 12h 1d 2d 7d].each do |schedule| - @rufus_scheduler.every schedule do - run_schedule "every_#{schedule}" - end - end - - # Schedule events for specific times. - - # Times are assumed to be in PST for now. Can store a user#timezone later. - 24.times do |hour| - @rufus_scheduler.cron "0 #{hour} * * * " + tzinfo_friendly_timezone do - if hour == 0 - run_schedule "midnight" - elsif hour < 12 - run_schedule "#{hour}am" - elsif hour == 12 - run_schedule "noon" - else - run_schedule "#{hour - 12}pm" - end - end - end - - @rufus_scheduler.join - end end diff --git a/spec/env.test b/spec/env.test index c086797c..924c8134 100644 --- a/spec/env.test +++ b/spec/env.test @@ -3,3 +3,4 @@ TWITTER_OAUTH_KEY=twitteroauthkey TWITTER_OAUTH_SECRET=twitteroauthsecret THIRTY_SEVEN_SIGNALS_OAUTH_KEY=TESTKEY THIRTY_SEVEN_SIGNALS_OAUTH_SECRET=TESTSECRET +FAILED_JOBS_TO_KEEP=2 \ No newline at end of file diff --git a/spec/lib/huginn_scheduler_spec.rb b/spec/lib/huginn_scheduler_spec.rb new file mode 100644 index 00000000..c1633ab4 --- /dev/null +++ b/spec/lib/huginn_scheduler_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +describe HuginnScheduler do + before(:each) do + @scheduler = HuginnScheduler.new + stub + end + + it "should stop the scheduler" do + mock.instance_of(Rufus::Scheduler).stop + @scheduler.stop + end + + it "schould register the schedules with the rufus scheduler and run" do + mock.instance_of(Rufus::Scheduler).join + @scheduler.run! + end + + it "should run scheduled agents" do + mock(Agent).run_schedule('every_1h') + mock.instance_of(IO).puts('Queuing schedule for every_1h') + @scheduler.send(:run_schedule, 'every_1h') + end + + it "should propagate events" do + mock(Agent).receive! + stub.instance_of(IO).puts + @scheduler.send(:propagate!) + end + + it "schould clean up expired events" do + mock(Event).cleanup_expired! + stub.instance_of(IO).puts + @scheduler.send(:cleanup_expired_events!) + end + + describe "#hour_to_schedule_name" do + it "for 0h" do + @scheduler.send(:hour_to_schedule_name, 0).should == 'midnight' + end + + it "for the forenoon" do + @scheduler.send(:hour_to_schedule_name, 6).should == '6am' + end + + it "for 12h" do + @scheduler.send(:hour_to_schedule_name, 12).should == 'noon' + end + + it "for the afternoon" do + @scheduler.send(:hour_to_schedule_name, 17).should == '5pm' + end + end + + describe "cleanup_failed_jobs!" do + before do + 3.times do |i| + Delayed::Job.create(failed_at: Time.now - i.minutes) + end + @keep = Delayed::Job.order(:failed_at)[1] + end + + it "work with set FAILED_JOBS_TO_KEEP env variable", focus: true do + expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(-1) + expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(0) + @keep.id.should == Delayed::Job.order(:failed_at)[0].id + end + + + it "work without the FAILED_JOBS_TO_KEEP env variable" do + old = ENV['FAILED_JOBS_TO_KEEP'] + ENV['FAILED_JOBS_TO_KEEP'] = nil + expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(0) + ENV['FAILED_JOBS_TO_KEEP'] = old + end + end +end \ No newline at end of file