say_when 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/Guardfile +50 -0
- data/README.md +135 -2
- data/Rakefile +1 -0
- data/lib/say_when.rb +33 -18
- data/lib/say_when/configuration.rb +16 -0
- data/lib/say_when/cron_expression.rb +19 -21
- data/lib/say_when/poller/base_poller.rb +108 -0
- data/lib/say_when/poller/celluloid_poller.rb +30 -0
- data/lib/say_when/poller/concurrent_poller.rb +31 -0
- data/lib/say_when/poller/simple_poller.rb +37 -0
- data/lib/say_when/processor/active_job_strategy.rb +35 -0
- data/lib/say_when/processor/simple_strategy.rb +13 -0
- data/lib/say_when/processor/test_strategy.rb +21 -0
- data/lib/say_when/scheduler.rb +67 -101
- data/lib/say_when/storage/active_record_strategy.rb +204 -0
- data/lib/say_when/storage/base_job.rb +96 -0
- data/lib/say_when/storage/memory_strategy.rb +140 -0
- data/lib/say_when/tasks.rb +15 -3
- data/lib/say_when/triggers/base.rb +3 -3
- data/lib/say_when/triggers/cron_strategy.rb +2 -3
- data/lib/say_when/triggers/instance_strategy.rb +3 -4
- data/lib/say_when/triggers/once_strategy.rb +3 -4
- data/lib/say_when/utils.rb +16 -0
- data/lib/say_when/version.rb +1 -1
- data/say_when.gemspec +10 -5
- data/test/minitest_helper.rb +45 -15
- data/test/say_when/configuration_test.rb +14 -0
- data/test/say_when/cron_expression_test.rb +140 -0
- data/test/say_when/poller/base_poller_test.rb +42 -0
- data/test/say_when/poller/celluloid_poller_test.rb +17 -0
- data/test/say_when/poller/concurrent_poller_test.rb +19 -0
- data/test/say_when/poller/simple_poller_test.rb +27 -0
- data/test/say_when/processor/active_job_strategy_test.rb +31 -0
- data/test/say_when/processor/simple_strategy_test.rb +15 -0
- data/test/say_when/scheduler_test.rb +41 -57
- data/test/say_when/storage/active_record_strategy_test.rb +134 -0
- data/test/say_when/storage/memory_strategy_test.rb +96 -0
- data/test/say_when/triggers/cron_strategy_test.rb +11 -0
- data/test/say_when/triggers/instance_strategy_test.rb +13 -0
- data/test/say_when/triggers/once_strategy_test.rb +2 -2
- data/test/say_when_test.rb +20 -0
- metadata +110 -36
- data/lib/say_when/base_job.rb +0 -96
- data/lib/say_when/processor/active_messaging.rb +0 -21
- data/lib/say_when/processor/base.rb +0 -19
- data/lib/say_when/processor/shoryuken.rb +0 -14
- data/lib/say_when/processor/simple.rb +0 -17
- data/lib/say_when/storage/active_record/acts.rb +0 -92
- data/lib/say_when/storage/active_record/job.rb +0 -100
- data/lib/say_when/storage/active_record/job_execution.rb +0 -14
- data/lib/say_when/storage/memory/base.rb +0 -36
- data/lib/say_when/storage/memory/job.rb +0 -53
- data/test/say_when/cron_expression_spec.rb +0 -74
- data/test/say_when/processor/active_messaging_test.rb +0 -41
- data/test/say_when/storage/active_record/job_test.rb +0 -90
- data/test/say_when/storage/memory/job_test.rb +0 -32
- data/test/say_when/storage/memory/trigger_test.rb +0 -54
- data/test/support/models.rb +0 -33
@@ -1,21 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'activemessaging/message_sender'
|
4
|
-
|
5
|
-
module SayWhen
|
6
|
-
module Processor
|
7
|
-
class ActiveMessaging < SayWhen::Processor::Base
|
8
|
-
|
9
|
-
include ::ActiveMessaging::MessageSender
|
10
|
-
|
11
|
-
def initialize(scheduler)
|
12
|
-
super(scheduler)
|
13
|
-
end
|
14
|
-
|
15
|
-
# send the job to the other end, then in the a13g processor, call the execute method
|
16
|
-
def process(job)
|
17
|
-
publish(:say_when, { job_id: job.id }.to_yaml )
|
18
|
-
end
|
19
|
-
end if defined?(::ActiveMessaging)
|
20
|
-
end
|
21
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module SayWhen
|
4
|
-
module Processor
|
5
|
-
|
6
|
-
class Base
|
7
|
-
attr_accessor :scheduler
|
8
|
-
|
9
|
-
def initialize(scheduler)
|
10
|
-
@scheduler = scheduler
|
11
|
-
end
|
12
|
-
|
13
|
-
def process(job)
|
14
|
-
raise NotImplementedError.new('You need to implement process(job)')
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module SayWhen #:nodoc:
|
4
|
-
module Storage #:nodoc:
|
5
|
-
module ActiveRecord #:nodoc:
|
6
|
-
module Acts #:nodoc:
|
7
|
-
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def acts_as_scheduled
|
12
|
-
include SayWhen::Storage::ActiveRecord::Acts::InstanceMethods
|
13
|
-
|
14
|
-
has_many :scheduled_jobs, as: :scheduled, class_name: 'SayWhen::Storage::ActiveRecord::Job', dependent: :destroy
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module InstanceMethods
|
19
|
-
|
20
|
-
def schedule_instance(next_at_method, job={})
|
21
|
-
options = job_options(job)
|
22
|
-
options[:trigger_strategy] = 'instance'
|
23
|
-
options[:trigger_options] = { next_at_method: next_at_method }
|
24
|
-
Scheduler.schedule(options)
|
25
|
-
end
|
26
|
-
|
27
|
-
def schedule_cron(expression, time_zone, job={})
|
28
|
-
options = job_options(job)
|
29
|
-
options[:trigger_strategy] = 'cron'
|
30
|
-
options[:trigger_options] = { expression: expression, time_zone: time_zone }
|
31
|
-
Scheduler.schedule(options)
|
32
|
-
end
|
33
|
-
|
34
|
-
def schedule_once(time, job={})
|
35
|
-
options = job_options(job)
|
36
|
-
options[:trigger_strategy] = 'once'
|
37
|
-
options[:trigger_options] = { at: time}
|
38
|
-
Scheduler.schedule(options)
|
39
|
-
end
|
40
|
-
|
41
|
-
def schedule_in(after, job={})
|
42
|
-
options = job_options(job)
|
43
|
-
options[:trigger_strategy] = 'once'
|
44
|
-
options[:trigger_options] = { at: (Time.now + after)}
|
45
|
-
Scheduler.schedule(options)
|
46
|
-
end
|
47
|
-
|
48
|
-
# helpers
|
49
|
-
|
50
|
-
def job_options(job)
|
51
|
-
{
|
52
|
-
scheduled: self,
|
53
|
-
job_class: extract_job_class(job),
|
54
|
-
job_method: extract_job_method(job),
|
55
|
-
data: extract_data(job)
|
56
|
-
}
|
57
|
-
end
|
58
|
-
|
59
|
-
def extract_job_class(job)
|
60
|
-
if job.is_a?(Hash)
|
61
|
-
job[:class]
|
62
|
-
elsif job.is_a?(Class)
|
63
|
-
job.name
|
64
|
-
elsif job.is_a?(String)
|
65
|
-
job
|
66
|
-
else
|
67
|
-
raise "Could not identify job class from: #{job}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def extract_job_method(job)
|
72
|
-
if job.is_a?(Hash)
|
73
|
-
job[:method]
|
74
|
-
else
|
75
|
-
'execute'
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def extract_data(job)
|
80
|
-
if job.is_a?(Hash)
|
81
|
-
job[:data]
|
82
|
-
else
|
83
|
-
nil
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end # InstanceMethods
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
ActiveRecord::Base.send(:include, SayWhen::Storage::ActiveRecord::Acts) unless ActiveRecord::Base.include?(SayWhen::Storage::ActiveRecord::Acts)
|
@@ -1,100 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'active_record'
|
4
|
-
require 'say_when/base_job'
|
5
|
-
require 'say_when/storage/active_record/job_execution'
|
6
|
-
require 'say_when/storage/active_record/acts'
|
7
|
-
|
8
|
-
module SayWhen
|
9
|
-
module Storage
|
10
|
-
module ActiveRecord
|
11
|
-
|
12
|
-
class Job < ::ActiveRecord::Base
|
13
|
-
|
14
|
-
include SayWhen::BaseJob
|
15
|
-
|
16
|
-
self.table_name = 'say_when_jobs'
|
17
|
-
|
18
|
-
serialize :trigger_options
|
19
|
-
serialize :data
|
20
|
-
|
21
|
-
belongs_to :scheduled, polymorphic: true
|
22
|
-
has_many :job_executions, class_name: 'SayWhen::Storage::ActiveRecord::JobExecution'
|
23
|
-
|
24
|
-
before_create :set_defaults
|
25
|
-
|
26
|
-
def self.acquire_next(no_later_than)
|
27
|
-
next_job = nil
|
28
|
-
|
29
|
-
hide_logging do
|
30
|
-
SayWhen::Storage::ActiveRecord::Job.transaction do
|
31
|
-
# select and lock the next job that needs executin' (status waiting, and after no_later_than)
|
32
|
-
next_job = where('status = ? and next_fire_at < ?', STATE_WAITING, no_later_than.in_time_zone('UTC')).
|
33
|
-
order('next_fire_at ASC').
|
34
|
-
lock(true).first
|
35
|
-
|
36
|
-
# set status to acquired to take it out of rotation
|
37
|
-
next_job.update_attribute(:status, STATE_ACQUIRED) unless next_job.nil?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
next_job
|
41
|
-
end
|
42
|
-
|
43
|
-
def set_defaults
|
44
|
-
# puts "SayWhen::Storage::ActiveRecord::Job - set_defaults start"
|
45
|
-
self.status = STATE_WAITING
|
46
|
-
self.next_fire_at = self.trigger.next_fire_at
|
47
|
-
# puts "SayWhen::Storage::ActiveRecord::Job - set_defaults, next_fire_at: #{self.next_fire_at}"
|
48
|
-
end
|
49
|
-
|
50
|
-
def fired(fired_at=Time.now)
|
51
|
-
Job.transaction {
|
52
|
-
super
|
53
|
-
self.save!
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
def release
|
58
|
-
Job.transaction {
|
59
|
-
super
|
60
|
-
self.save!
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
# default impl with some error handling and result recording
|
65
|
-
def execute
|
66
|
-
result = nil
|
67
|
-
execution = SayWhen::Storage::ActiveRecord::JobExecution.create(:job=>self, :status=>'executing', :start_at=>Time.now)
|
68
|
-
|
69
|
-
begin
|
70
|
-
result = self.execute_job(data)
|
71
|
-
execution.result = result
|
72
|
-
execution.status = 'complete'
|
73
|
-
rescue Object=>ex
|
74
|
-
execution.result = "#{ex.class.name}: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}"
|
75
|
-
execution.status = 'error'
|
76
|
-
end
|
77
|
-
|
78
|
-
execution.end_at = Time.now
|
79
|
-
execution.save!
|
80
|
-
result
|
81
|
-
end
|
82
|
-
|
83
|
-
protected
|
84
|
-
|
85
|
-
def self.hide_logging
|
86
|
-
old_logger = nil
|
87
|
-
begin
|
88
|
-
old_logger = ::ActiveRecord::Base.logger
|
89
|
-
::ActiveRecord::Base.logger = nil
|
90
|
-
|
91
|
-
yield
|
92
|
-
|
93
|
-
ensure
|
94
|
-
::ActiveRecord::Base.logger = old_logger
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'active_record'
|
4
|
-
|
5
|
-
module SayWhen
|
6
|
-
module Storage
|
7
|
-
module ActiveRecord
|
8
|
-
class JobExecution < ::ActiveRecord::Base
|
9
|
-
self.table_name = "say_when_job_executions"
|
10
|
-
belongs_to :job, class_name: 'SayWhen::Storage::ActiveRecord::Job'
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module SayWhen
|
4
|
-
module Storage
|
5
|
-
module Memory
|
6
|
-
|
7
|
-
module Base
|
8
|
-
|
9
|
-
attr_accessor :props
|
10
|
-
|
11
|
-
def has_properties(*args)
|
12
|
-
@props ||= []
|
13
|
-
args.each do |a|
|
14
|
-
unless @props.member?(a.to_s)
|
15
|
-
@props << a.to_s
|
16
|
-
class_eval { attr_accessor(a.to_sym) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.included(base)
|
22
|
-
base.extend self
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(args={})
|
26
|
-
args.each do |k,v|
|
27
|
-
if self.class.props.member?(k.to_s)
|
28
|
-
self.send("#{k}=", v)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'say_when/storage/memory/base'
|
4
|
-
|
5
|
-
module SayWhen
|
6
|
-
module Storage
|
7
|
-
module Memory
|
8
|
-
|
9
|
-
# define a trigger class
|
10
|
-
class Job
|
11
|
-
|
12
|
-
include SayWhen::Storage::Memory::Base
|
13
|
-
include SayWhen::BaseJob
|
14
|
-
|
15
|
-
has_properties :group, :name, :status, :start_at, :end_at
|
16
|
-
has_properties :trigger_strategy, :trigger_options, :last_fire_at, :next_fire_at
|
17
|
-
has_properties :job_class, :job_method, :data
|
18
|
-
has_properties :scheduled
|
19
|
-
|
20
|
-
cattr_accessor :jobs
|
21
|
-
@@jobs = SortedSet.new
|
22
|
-
@@acquire_lock = Mutex.new
|
23
|
-
|
24
|
-
def self.acquire_next(no_later_than)
|
25
|
-
@@acquire_lock.synchronize {
|
26
|
-
|
27
|
-
next_job = jobs.detect(nil) do |j|
|
28
|
-
(j.status == STATE_WAITING) && (j.next_fire_at.to_i <= no_later_than.to_i)
|
29
|
-
end
|
30
|
-
|
31
|
-
next_job.status = STATE_ACQUIRED if next_job
|
32
|
-
next_job
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.create(job)
|
37
|
-
job = new(job) if job.is_a?(Hash)
|
38
|
-
self.jobs << job
|
39
|
-
end
|
40
|
-
|
41
|
-
def initialize(options={})
|
42
|
-
super
|
43
|
-
self.status = STATE_WAITING unless self.status
|
44
|
-
self.next_fire_at = trigger.next_fire_at
|
45
|
-
end
|
46
|
-
|
47
|
-
def <=>(job)
|
48
|
-
self.next_fire_at.to_i <=> job.next_fire_at.to_i
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
4
|
-
|
5
|
-
describe SayWhen::CronExpression do
|
6
|
-
|
7
|
-
it 'should set the time_zone' do
|
8
|
-
@ce = SayWhen::CronExpression.new("0 0 12 ? * 1#1 *", 'Pacific Time (US & Canada)')
|
9
|
-
@ce.time_zone.must_equal 'Pacific Time (US & Canada)'
|
10
|
-
end
|
11
|
-
|
12
|
-
describe 'get first sunday in the month with "1#1' do
|
13
|
-
|
14
|
-
before do
|
15
|
-
@ce = SayWhen::CronExpression.new("0 0 12 ? * 1#1 *", 'Pacific Time (US & Canada)')
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'finds first sunday in the same month' do
|
19
|
-
@ce.next_fire_at(Time.utc(2008,1,1)).must_equal Time.parse('2008-01-06 12:00:00 -0800')
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
it 'finds first sunday in the next month' do
|
24
|
-
@ce.next_fire_at(Time.utc(2008,1,7)).must_equal Time.parse('2008-02-03 12:00:00 -0800')
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'finds last sunday in the same month' do
|
28
|
-
@ce.last_fire_at(Time.utc(2008,1,10)).must_equal Time.parse('2008-01-06 12:00:00 -0800')
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'finds sundays in the prior months and years' do
|
32
|
-
@ce.last_fire_at(Time.utc(2008,1,5)).must_equal Time.parse('2007-12-02 12:00:00 -0800')
|
33
|
-
@ce.last_fire_at(Time.parse('2007-12-02 12:00:00 -0800') - 1.second).must_equal Time.parse('2007-11-04 12:00:00 -0800')
|
34
|
-
@ce.last_fire_at(Time.parse('2007-11-04 12:00:00 -0800') - 1.second).must_equal Time.parse('2007-10-07 12:00:00 -0700')
|
35
|
-
@ce.next_fire_at(Time.parse('2007-10-07 12:00:00 -0700') + 1.second).must_equal Time.parse('2007-11-04 12:00:00 -0800')
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe 'get last sunday in the month with "1L"' do
|
40
|
-
before do
|
41
|
-
@ce = SayWhen::CronExpression.new("0 0 12 ? * 1L *", 'Pacific Time (US & Canada)')
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'gets next final sunday for same month' do
|
45
|
-
@ce.next_fire_at(Time.utc(2008,1,1)).must_equal Time.parse('2008-01-27 12:00:00 -0800')
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
it 'gets next final sunday for next month' do
|
50
|
-
@ce.next_fire_at(Time.utc(2008,1,28)).must_equal Time.parse('2008-02-24 12:00:00 -0800')
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'gets last final sunday for same month' do
|
54
|
-
@ce.last_fire_at(Time.utc(2008,1,28)).must_equal Time.parse('2008-01-27 12:00:00 -0800')
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'gets last sunday for prior month and year' do
|
58
|
-
@ce.last_fire_at(Time.utc(2008,1,1)).must_equal Time.parse('2007-12-30 12:00:00 -0800')
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
it 'gets last sunday for prior month and year' do
|
63
|
-
nfa = @ce.last_fire_at(Time.utc(2007,12,1))
|
64
|
-
nfa.must_equal Time.parse('2007-11-25 12:00:00 -0800')
|
65
|
-
|
66
|
-
nfa = @ce.last_fire_at(nfa - 1.second)
|
67
|
-
nfa.must_equal Time.parse('2007-10-28 12:00:00 -0700')
|
68
|
-
|
69
|
-
nfa = @ce.next_fire_at(nfa + 1.second)
|
70
|
-
nfa.must_equal Time.parse('2007-11-25 12:00:00 -0800')
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|