From b89c222edcd875a3f7964ec2438596a9458aa486 Mon Sep 17 00:00:00 2001 From: Susan Wright Date: Tue, 7 Mar 2017 16:04:39 -0700 Subject: [PATCH 1/4] Minor clean up, make this function easier to read --- lib/clockwork/event.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/clockwork/event.rb b/lib/clockwork/event.rb index 50b197d..afd08a8 100644 --- a/lib/clockwork/event.rb +++ b/lib/clockwork/event.rb @@ -21,7 +21,10 @@ def convert_timezone(t) def run_now?(t) t = convert_timezone(t) - elapsed_ready(t) and (@at.nil? or @at.ready?(t)) and (@if.nil? or @if.call(t)) + return false unless elapsed_ready?(t) + return false unless run_at?(t) + return false unless run_if?(t) + true end def thread? @@ -57,10 +60,18 @@ def execute @manager.handle_error e end - def elapsed_ready(t) + def elapsed_ready?(t) @last.nil? || (t - @last.to_i).to_i >= @period end + def run_at?(t) + @at.nil? || @at.ready?(t) + end + + def run_if?(t) + @if.nil? || @if.call(t) + end + def validate_if_option(if_option) if if_option && !if_option.respond_to?(:call) raise ArgumentError.new(':if expects a callable object, but #{if_option} does not respond to call') From e332e6dece7403ff01425cde3dc8419d2a0507cb Mon Sep 17 00:00:00 2001 From: Susan Wright Date: Tue, 7 Mar 2017 17:03:35 -0700 Subject: [PATCH 2/4] Tests around 'skip_first_run_option' --- test/event_test.rb | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/event_test.rb b/test/event_test.rb index 566a426..2ef77b6 100644 --- a/test/event_test.rb +++ b/test/event_test.rb @@ -34,4 +34,41 @@ end end end + + describe '#run_now?' do + before do + @manager = Class.new + @manager.stubs(:config).returns({}) + end + + describe 'event skip_first_run option set to true' do + it 'returns false on first attempt' do + event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => true) + assert_equal false, event.run_now?(Time.now) + end + + it 'returns true on subsequent attempts' do + event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => true) + # first run + event.run_now?(Time.now) + + # second run + assert_equal true, event.run_now?(Time.now + 1) + end + end + + describe 'event skip_first_run option not set' do + it 'returns true on first attempt' do + event = Clockwork::Event.new(@manager, 1, nil, nil) + assert_equal true, event.run_now?(Time.now + 1) + end + end + + describe 'event skip_first_run option set to false' do + it 'returns true on first attempt' do + event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => false) + assert_equal true, event.run_now?(Time.now) + end + end + end end From d2d47d8ccaeb1f30ae7e38b2298754020843f74b Mon Sep 17 00:00:00 2001 From: Susan Wright Date: Tue, 7 Mar 2017 17:03:56 -0700 Subject: [PATCH 3/4] Add functionality for 'skip_first_run' option --- lib/clockwork/event.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/clockwork/event.rb b/lib/clockwork/event.rb index afd08a8..7e6538f 100644 --- a/lib/clockwork/event.rb +++ b/lib/clockwork/event.rb @@ -8,11 +8,12 @@ def initialize(manager, period, job, block, options={}) @period = period @job = job @at = At.parse(options[:at]) - @last = nil @block = block @if = options[:if] @thread = options.fetch(:thread, @manager.config[:thread]) @timezone = options.fetch(:tz, @manager.config[:tz]) + @skip_first_run = options[:skip_first_run] + @last = @skip_first_run ? convert_timezone(Time.now) : nil end def convert_timezone(t) From 8f8b85d5c9681bf6df4e7b6e663dba056294022d Mon Sep 17 00:00:00 2001 From: Susan Wright Date: Tue, 11 Jul 2017 15:34:58 -0600 Subject: [PATCH 4/4] Add snippet to readme about 'skip_first_run' --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 079caf8..54a1913 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,19 @@ Clockwork.every(1.day, 'run.me.in.new.thread', :thread => true) If a job is long-running or IO-intensive, this option helps keep the clock precise. +### :skip_first_run + +Normally, a clockwork process that is defined to run in a specified period will run at startup. +This is sometimes undesired behaviour, if the action being run relies on other processes booting which may be slower than clock. +To avoid this problem, `:skip_first_run` can be used. + +```ruby +Clockwork.every(5.minutes, 'myjob', :skip_first_run => true) +``` + +The above job will not run at initial boot, and instead run every 5 minutes after boot. + + Configuration -----------------------