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
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'celluloid/current'
|
4
|
+
require 'logger'
|
5
|
+
require 'say_when/poller/base_poller'
|
6
|
+
|
7
|
+
module SayWhen
|
8
|
+
module Poller
|
9
|
+
class CelluloidPoller
|
10
|
+
include Celluloid
|
11
|
+
include SayWhen::Poller::BasePoller
|
12
|
+
|
13
|
+
def initialize(tick = nil)
|
14
|
+
@tick_length = tick.to_i if tick
|
15
|
+
start
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
@tick_timer = every(tick_length) { process_jobs }
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop
|
23
|
+
if @tick_timer
|
24
|
+
@tick_timer.cancel
|
25
|
+
@tick_timer = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'concurrent'
|
4
|
+
require 'logger'
|
5
|
+
require 'say_when/poller/base_poller'
|
6
|
+
|
7
|
+
module SayWhen
|
8
|
+
module Poller
|
9
|
+
class ConcurrentPoller
|
10
|
+
include SayWhen::Poller::BasePoller
|
11
|
+
|
12
|
+
def initialize(tick = nil)
|
13
|
+
@tick_length = tick.to_i if tick
|
14
|
+
start
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
@tick_timer = Concurrent::TimerTask.new(execution_interval: tick_length) do
|
19
|
+
process_jobs
|
20
|
+
end.tap(&:execute)
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop
|
24
|
+
if @tick_timer
|
25
|
+
@tick_timer.shutdown
|
26
|
+
@tick_timer = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'say_when/poller/base_poller'
|
4
|
+
|
5
|
+
module SayWhen
|
6
|
+
module Poller
|
7
|
+
class SimplePoller
|
8
|
+
include SayWhen::Poller::BasePoller
|
9
|
+
|
10
|
+
attr_accessor :running
|
11
|
+
|
12
|
+
def initialize(tick = nil)
|
13
|
+
self.tick_length = tick.to_i if tick
|
14
|
+
self.running = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def running?
|
18
|
+
!!running
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
self.running = true
|
23
|
+
logger.info "SayWhen::SimplePoller started"
|
24
|
+
while running
|
25
|
+
process_jobs
|
26
|
+
tick
|
27
|
+
end
|
28
|
+
logger.info "SayWhen::SimplePoller stopped"
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop
|
32
|
+
logger.info "SayWhen::SimplePoller stopping..."
|
33
|
+
self.running = false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'active_job'
|
4
|
+
|
5
|
+
module SayWhen
|
6
|
+
module Processor
|
7
|
+
class ActiveJobStrategy
|
8
|
+
class << self
|
9
|
+
def process(job)
|
10
|
+
SayWhenJob.perform_later(job_to_arg(job))
|
11
|
+
end
|
12
|
+
|
13
|
+
def job_to_arg(job)
|
14
|
+
case job
|
15
|
+
when GlobalID::Identification
|
16
|
+
job
|
17
|
+
else
|
18
|
+
{ class: job.class.name, attributes: job.to_hash }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SayWhenJob < ActiveJob::Base
|
24
|
+
queue_as SayWhen.options[:queue]
|
25
|
+
|
26
|
+
def perform(job)
|
27
|
+
if job.is_a?(Hash)
|
28
|
+
job = job[:class].constantize.new(job[:attributes])
|
29
|
+
end
|
30
|
+
job.execute
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SayWhen
|
4
|
+
module Processor
|
5
|
+
class TestStrategy
|
6
|
+
class << self
|
7
|
+
def process(job)
|
8
|
+
self.jobs << job
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset
|
12
|
+
self.jobs = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def jobs
|
16
|
+
@jobs ||= []
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/say_when/scheduler.rb
CHANGED
@@ -1,133 +1,99 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'say_when/utils'
|
4
|
+
|
3
5
|
module SayWhen
|
4
6
|
class Scheduler
|
7
|
+
include SayWhen::Utils
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
attr_accessor :running
|
9
|
+
# When passing in a job, can be a Hash, String, or Class
|
10
|
+
# Hash: { class: '<class name>' } or { job_class: '<class name>' }
|
11
|
+
# String: '<class name>'
|
12
|
+
# Class: <job class>
|
13
|
+
def schedule(job)
|
14
|
+
storage.create(job)
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def schedule_cron(expression, job)
|
18
|
+
time_zone = if job.is_a?(Hash)
|
19
|
+
job.delete(:time_zone)
|
20
|
+
end || 'UTC'
|
21
|
+
options = job_options(job)
|
22
|
+
options[:trigger_strategy] = :cron
|
23
|
+
options[:trigger_options] = { expression: expression, time_zone: time_zone }
|
24
|
+
schedule(options)
|
25
|
+
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
def schedule_instance(next_at_method = 'next_fire_at', job = {})
|
28
|
+
options = job_options(job)
|
29
|
+
options[:trigger_strategy] = 'instance'
|
30
|
+
options[:trigger_options] = { next_at_method: next_at_method }
|
31
|
+
schedule(options)
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
def schedule_once(time, job = {})
|
35
|
+
options = job_options(job)
|
36
|
+
options[:trigger_strategy] = 'once'
|
37
|
+
options[:trigger_options] = { at: time}
|
38
|
+
schedule(options)
|
39
|
+
end
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
+
schedule(options)
|
36
46
|
end
|
37
47
|
|
38
|
-
def
|
39
|
-
|
48
|
+
def job_options(job)
|
49
|
+
{
|
50
|
+
scheduled: extract_scheduled(job),
|
51
|
+
job_class: extract_job_class(job),
|
52
|
+
job_method: extract_job_method(job),
|
53
|
+
data: extract_data(job)
|
54
|
+
}
|
40
55
|
end
|
41
56
|
|
42
|
-
def
|
43
|
-
if
|
44
|
-
@processor_class ||= DEFAULT_PROCESSOR_CLASS
|
45
|
-
@processor = @processor_class.new(self)
|
46
|
-
end
|
47
|
-
@processor
|
57
|
+
def extract_scheduled(job)
|
58
|
+
job[:scheduled] if job.is_a?(Hash)
|
48
59
|
end
|
49
60
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
begin
|
58
|
-
|
59
|
-
self.running = true
|
60
|
-
|
61
|
-
logger.info "SayWhen::Scheduler running"
|
62
|
-
job = nil
|
63
|
-
while running
|
64
|
-
begin
|
65
|
-
time_now = Time.now
|
66
|
-
logger.debug "SayWhen:: Looking for job that should be ready to fire before #{time_now}"
|
67
|
-
job = job_class.acquire_next(time_now)
|
68
|
-
if job.nil?
|
69
|
-
logger.debug "SayWhen:: no jobs to acquire, sleep"
|
70
|
-
sleep(tick_length)
|
71
|
-
else
|
72
|
-
logger.debug "SayWhen:: got a job: #{job.inspect}"
|
73
|
-
# delegate processing the trigger to the processor
|
74
|
-
self.processor.process(job)
|
75
|
-
logger.debug "SayWhen:: job processed"
|
76
|
-
|
77
|
-
# this should update next fire at, and put back in list of scheduled jobs
|
78
|
-
job.fired(time_now)
|
79
|
-
logger.debug "SayWhen:: job fired complete"
|
80
|
-
end
|
81
|
-
rescue StandardError => ex
|
82
|
-
job_msg = job && "job: #{job.inspect} "
|
83
|
-
logger.error "SayWhen:: Failure: #{job_msg}exception: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
|
84
|
-
safe_release(job)
|
85
|
-
sleep(tick_length)
|
86
|
-
rescue Interrupt => ex
|
87
|
-
job_msg = job && "\n - interrupted job: #{job.inspect}\n"
|
88
|
-
logger.error "\nSayWhen:: Interrupt! #{ex.inspect}#{job_msg}"
|
89
|
-
safe_release(job)
|
90
|
-
exit
|
91
|
-
rescue Exception => ex
|
92
|
-
job_msg = job && "job: #{job.inspect} "
|
93
|
-
logger.error "SayWhen:: Exception: #{job_msg}exception: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
|
94
|
-
safe_release(job)
|
95
|
-
exit
|
96
|
-
end
|
97
|
-
end
|
61
|
+
def extract_job_class(job)
|
62
|
+
job_class = if job.is_a?(Hash)
|
63
|
+
job[:class] || job[:job_class]
|
64
|
+
elsif job.is_a?(Class)
|
65
|
+
job.name
|
66
|
+
elsif job.is_a?(String)
|
67
|
+
job
|
98
68
|
end
|
99
69
|
|
100
|
-
|
101
|
-
|
70
|
+
if !job_class
|
71
|
+
raise "Could not identify job class from: #{job}"
|
72
|
+
end
|
102
73
|
|
103
|
-
|
104
|
-
job.release if job
|
105
|
-
rescue
|
106
|
-
logger "Failed to release job: #{job.inspect}" rescue nil
|
74
|
+
job_class
|
107
75
|
end
|
108
76
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
77
|
+
def extract_job_method(job)
|
78
|
+
if job.is_a?(Hash)
|
79
|
+
job[:method] || job[:job_method]
|
80
|
+
end || 'execute'
|
112
81
|
end
|
113
82
|
|
114
|
-
def
|
115
|
-
|
83
|
+
def extract_data(job)
|
84
|
+
job[:data] if job && job.is_a?(Hash)
|
116
85
|
end
|
117
86
|
|
118
|
-
def
|
119
|
-
|
120
|
-
require "say_when/storage/#{strategy}/job"
|
121
|
-
job_class_name = "SayWhen::Storage::#{strategy.to_s.camelize}::Job"
|
122
|
-
job_class_name.constantize
|
87
|
+
def storage=(s)
|
88
|
+
@storage = s
|
123
89
|
end
|
124
90
|
|
125
|
-
def
|
126
|
-
|
91
|
+
def storage
|
92
|
+
@storage ||= load_strategy(:storage, SayWhen.options[:storage_strategy])
|
127
93
|
end
|
128
94
|
|
129
95
|
def logger
|
130
|
-
SayWhen
|
96
|
+
SayWhen.logger
|
131
97
|
end
|
132
98
|
end
|
133
99
|
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'say_when/storage/base_job'
|
3
|
+
|
4
|
+
module SayWhen
|
5
|
+
module Storage
|
6
|
+
class ActiveRecordStrategy
|
7
|
+
class << self
|
8
|
+
def acquire_next(no_later_than = nil)
|
9
|
+
SayWhen::Storage::ActiveRecordStrategy::Job.acquire_next(no_later_than)
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset_acquired(older_than_seconds)
|
13
|
+
SayWhen::Storage::ActiveRecordStrategy::Job.reset_acquired(older_than_seconds)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(job)
|
17
|
+
SayWhen::Storage::ActiveRecordStrategy::Job.job_create(job)
|
18
|
+
end
|
19
|
+
|
20
|
+
def fired(job, fired_at = Time.now)
|
21
|
+
job.fired(fired_at)
|
22
|
+
end
|
23
|
+
|
24
|
+
def release(job)
|
25
|
+
job.release
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialize(job)
|
29
|
+
job
|
30
|
+
end
|
31
|
+
|
32
|
+
def deserialize(job)
|
33
|
+
job
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class JobExecution < ActiveRecord::Base
|
38
|
+
self.table_name = 'say_when_job_executions'
|
39
|
+
belongs_to :job, class_name: 'SayWhen::Storage::ActiveRecordStrategy::Job'
|
40
|
+
end
|
41
|
+
|
42
|
+
class Job < ActiveRecord::Base
|
43
|
+
include SayWhen::Storage::BaseJob
|
44
|
+
|
45
|
+
self.table_name = 'say_when_jobs'
|
46
|
+
|
47
|
+
serialize :trigger_options
|
48
|
+
serialize :data
|
49
|
+
|
50
|
+
belongs_to :scheduled, polymorphic: true
|
51
|
+
has_many :job_executions, class_name: 'SayWhen::Storage::ActiveRecordStrategy::JobExecution'
|
52
|
+
|
53
|
+
before_create :set_defaults
|
54
|
+
|
55
|
+
def self.job_create(job)
|
56
|
+
if existing_job = find_named_job(job[:group], job[:name])
|
57
|
+
existing_job.tap { |j| j.update_attributes(job) }
|
58
|
+
else
|
59
|
+
create(job)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.find_named_job(group, name)
|
64
|
+
group && name && where(name: name, group: group).first
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.acquire_next(no_later_than = nil)
|
68
|
+
next_job = nil
|
69
|
+
no_later_than = (no_later_than || Time.now).in_time_zone('UTC')
|
70
|
+
|
71
|
+
check_connection
|
72
|
+
hide_logging do
|
73
|
+
SayWhen::Storage::ActiveRecordStrategy::Job.transaction do
|
74
|
+
# select and lock the next job that needs executin' (status waiting, and after no_later_than)
|
75
|
+
next_job = where(status: STATE_WAITING).
|
76
|
+
where('next_fire_at < ?', no_later_than).
|
77
|
+
order('next_fire_at ASC').
|
78
|
+
lock(true).
|
79
|
+
first
|
80
|
+
|
81
|
+
# set status to acquired to take it out of rotation
|
82
|
+
next_job.update_attribute(:status, STATE_ACQUIRED) if next_job
|
83
|
+
end
|
84
|
+
end
|
85
|
+
next_job
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.reset_acquired(older_than_seconds)
|
89
|
+
return unless older_than_seconds.to_i > 0
|
90
|
+
older_than = (Time.now - older_than_seconds.to_i)
|
91
|
+
where('status = ? and updated_at < ?', STATE_ACQUIRED, older_than).update_all("status = '#{STATE_WAITING}'")
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.check_connection
|
95
|
+
if ActiveRecord::Base.respond_to?(:clear_active_connections!)
|
96
|
+
ActiveRecord::Base.clear_active_connections!
|
97
|
+
elsif ActiveRecord::Base.respond_to?(:verify_active_connections!)
|
98
|
+
ActiveRecord::Base.verify_active_connections!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.hide_logging
|
103
|
+
old_logger = nil
|
104
|
+
begin
|
105
|
+
old_logger = ::ActiveRecord::Base.logger
|
106
|
+
::ActiveRecord::Base.logger = nil
|
107
|
+
yield
|
108
|
+
ensure
|
109
|
+
::ActiveRecord::Base.logger = old_logger
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_defaults
|
114
|
+
self.status = STATE_WAITING
|
115
|
+
self.next_fire_at = self.trigger.next_fire_at
|
116
|
+
end
|
117
|
+
|
118
|
+
def fired(fired_at=Time.now)
|
119
|
+
self.class.transaction {
|
120
|
+
super
|
121
|
+
self.save!
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def release
|
126
|
+
self.class.transaction {
|
127
|
+
super
|
128
|
+
self.save!
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
# default impl with some error handling and result recording
|
133
|
+
def execute
|
134
|
+
result = nil
|
135
|
+
execution = JobExecution.create(job: self, status: STATE_EXECUTING, start_at: Time.now)
|
136
|
+
|
137
|
+
begin
|
138
|
+
result = self.execute_job(data)
|
139
|
+
execution.result = result
|
140
|
+
execution.status = 'complete'
|
141
|
+
rescue Object => ex
|
142
|
+
execution.result = "#{ex.class.name}: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}"
|
143
|
+
execution.status = 'error'
|
144
|
+
end
|
145
|
+
|
146
|
+
execution.end_at = Time.now
|
147
|
+
execution.save!
|
148
|
+
result
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module Acts #:nodoc:
|
153
|
+
extend ActiveSupport::Concern
|
154
|
+
|
155
|
+
module ClassMethods
|
156
|
+
def acts_as_scheduled
|
157
|
+
include SayWhen::Storage::ActiveRecordStrategy::Acts::InstanceMethods
|
158
|
+
|
159
|
+
has_many :scheduled_jobs,
|
160
|
+
as: :scheduled,
|
161
|
+
class_name: 'SayWhen::Storage::ActiveRecordStrategy::Job',
|
162
|
+
dependent: :destroy
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
module InstanceMethods
|
167
|
+
def schedule(job)
|
168
|
+
Scheduler.schedule(set_scheduled(job))
|
169
|
+
end
|
170
|
+
|
171
|
+
def schedule_instance(next_at_method = 'next_fire_at', job = {})
|
172
|
+
Scheduler.schedule_instance(next_at_method, set_scheduled(job))
|
173
|
+
end
|
174
|
+
|
175
|
+
def schedule_cron(expression, job = {})
|
176
|
+
Scheduler.schedule_cron(expression, set_scheduled(job))
|
177
|
+
end
|
178
|
+
|
179
|
+
def schedule_once(time, job = {})
|
180
|
+
Scheduler.schedule_once(time, set_scheduled(job))
|
181
|
+
end
|
182
|
+
|
183
|
+
def schedule_in(after, job = {})
|
184
|
+
Scheduler.schedule_in(after, set_scheduled(job))
|
185
|
+
end
|
186
|
+
|
187
|
+
def set_scheduled(job)
|
188
|
+
if job.is_a?(Hash)
|
189
|
+
job[:scheduled] = self
|
190
|
+
elsif job.respond_to?(:scheduled)
|
191
|
+
job.scheduled = self
|
192
|
+
end
|
193
|
+
job
|
194
|
+
end
|
195
|
+
end # InstanceMethods
|
196
|
+
end # class << self
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
aas = SayWhen::Storage::ActiveRecordStrategy::Acts
|
202
|
+
unless ActiveRecord::Base.include?(aas)
|
203
|
+
ActiveRecord::Base.send(:include, aas)
|
204
|
+
end
|