say_when 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|