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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92b39148a95c13f3b9fc5d55d56ef49d3566576f
|
4
|
+
data.tar.gz: d30b25ecd756ae2eb187a70c7511578fb0ddfc74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62ac59b8bd6d443cde57281aa883e3aaedba830737c4c9ea296914fd1c032628c9d316b5b9f920895bcc226694ab9e1568eb03dee8a759533cca671cb6afac3f
|
7
|
+
data.tar.gz: 0a30ee197ca109d14c57377f1c55c48d9e8f3b337a7a062dab0c93adf70e508e942e825420cbde5eb8b6fee2ec61a7a174ebb58be93081a55d8644dc5ec13156
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
9
|
+
|
10
|
+
## Guard internally checks for changes in the Guardfile and exits.
|
11
|
+
## If you want Guard to automatically start up again, run guard in a
|
12
|
+
## shell loop, e.g.:
|
13
|
+
##
|
14
|
+
## $ while bundle exec guard; do echo "Restarting Guard..."; done
|
15
|
+
##
|
16
|
+
## Note: if you are using the `directories` clause above and you are not
|
17
|
+
## watching the project directory ('.'), then you will want to move
|
18
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
19
|
+
#
|
20
|
+
# $ mkdir config
|
21
|
+
# $ mv Guardfile config/
|
22
|
+
# $ ln -s config/Guardfile .
|
23
|
+
#
|
24
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
25
|
+
|
26
|
+
guard :minitest do
|
27
|
+
# with Minitest::Unit
|
28
|
+
watch(%r{^test/(.*)\/?(.*)_test\.rb$})
|
29
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
|
30
|
+
watch(%r{^test/minitest_helper\.rb$}) { 'test' }
|
31
|
+
|
32
|
+
# with Minitest::Spec
|
33
|
+
# watch(%r{^spec/(.*)_spec\.rb$})
|
34
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
35
|
+
# watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
|
36
|
+
|
37
|
+
# Rails 4
|
38
|
+
# watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
39
|
+
# watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
|
40
|
+
# watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
|
41
|
+
# watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
|
42
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
|
43
|
+
# watch(%r{^test/.+_test\.rb$})
|
44
|
+
# watch(%r{^test/test_helper\.rb$}) { 'test' }
|
45
|
+
|
46
|
+
# Rails < 4
|
47
|
+
# watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
|
48
|
+
# watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
|
49
|
+
# watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
|
50
|
+
end
|
data/README.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
# SayWhen
|
2
2
|
|
3
|
-
|
3
|
+
SayWhen is a job scheduling library for use in any project, but with a few extra hooks for rails projects.
|
4
|
+
It was roughly inspired by the [Quartz scheduler](http://quartz-scheduler.org/).
|
5
|
+
|
6
|
+
You add it to a ruby program (optionally configure it) and then schedule jobs using a few different strategies, with cron-like expressions the most powerful.
|
7
|
+
|
8
|
+
When scheduling, you specify a trigger which controls when execution will occur, such as a cron trigger, or an execute only once trigger, and a job, which is the actual work to perform.
|
9
|
+
|
10
|
+
The cron triggers are based on the [extended cron capabilities](http://wiki.opensymphony.com/display/QRTZ1/CronTriggers+Tutorial).
|
11
|
+
|
12
|
+
Jobs can be stored different ways, either in memory (e.g. loaded on start from a ruby file), or saved to a database.
|
13
|
+
|
14
|
+
The scheduler can execute the jobs in different ways, either by loading and running them itself synchronously, or by delegating the processing to ActiveJob.
|
15
|
+
|
16
|
+
SayWhen can be run either in its own process, or can run as a supervised actor in a Celluloid process (e.g. sidekiq or shoryuken).
|
4
17
|
|
5
18
|
## Installation
|
6
19
|
|
@@ -18,9 +31,129 @@ Or install it yourself as:
|
|
18
31
|
|
19
32
|
$ gem install say_when
|
20
33
|
|
34
|
+
## Configuration
|
35
|
+
|
36
|
+
To use, first configure how jobs are stored and processed.
|
37
|
+
Be default, they are in memory, and processed synchronously, but that can be configured to behave differently.
|
38
|
+
|
39
|
+
The currently available storage options are:
|
40
|
+
- Memory (default) - usually jobs are initialized in code on load
|
41
|
+
- ActiveRecord - stores the scheduled jobs and can log execution information to database tables
|
42
|
+
|
43
|
+
The processor options are:
|
44
|
+
- Simple - the scheduler process executes the job itself synchronously
|
45
|
+
- ActiveJob - delegates the work to an ActiveJob async call
|
46
|
+
- Test - stubs out processing, useful for testing only
|
47
|
+
|
48
|
+
You also have some options for running SayWhen:
|
49
|
+
- SimplePoller - just a simple looping process, can be started with rake
|
50
|
+
- CelluloidPoller - defines a Celluloid Actor appropriate for adding to a running Celluloid process, such as from Shoryuken
|
51
|
+
|
52
|
+
Finally, there are options for triggers that determine when jobs run:
|
53
|
+
- Cron expression
|
54
|
+
- Once
|
55
|
+
- Instance
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# config/intializers/say_when.rb
|
59
|
+
|
60
|
+
require 'say_when'
|
61
|
+
|
62
|
+
# you can specify a the logger
|
63
|
+
SayWhen.logger = Rails.logger
|
64
|
+
|
65
|
+
# configure the scheduler for how to store and process scheduled jobs
|
66
|
+
# it will default to a :memory strategy and :simple processor
|
67
|
+
SayWhen.configure do |options|
|
68
|
+
options[:storage_strategy] = :active_record
|
69
|
+
options[:processor_strategy] = :simple
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
21
73
|
## Usage
|
22
74
|
|
23
|
-
|
75
|
+
### Basics
|
76
|
+
There is a very verbose way to create a scheduled job, setting the options for the trigger and job explicitly, and then some helper methods that make this easier for common cases.
|
77
|
+
|
78
|
+
Here is an example of the verbose way of scheduling a job, which is a good place to start:
|
79
|
+
```ruby
|
80
|
+
|
81
|
+
job = SayWhen::Scheduler.schedule(
|
82
|
+
trigger_strategy: 'once',
|
83
|
+
trigger_options: { at: 10.second.since },
|
84
|
+
job_class: SomeTask,
|
85
|
+
job_method: 'execute',
|
86
|
+
data: { id: 123 }
|
87
|
+
)
|
88
|
+
```
|
89
|
+
|
90
|
+
There are also convenience methods on the `Scheduler`:
|
91
|
+
```ruby
|
92
|
+
|
93
|
+
```
|
94
|
+
## ActiveRecord integration
|
95
|
+
|
96
|
+
Besides storing jobs in ActiveRecord, you can also associate jobs with other models.
|
97
|
+
|
98
|
+
There is an `acts_as_scheduled` method you can call in an ActiveRecord class for this purpose.
|
99
|
+
It both makes it easier to schedule a job, and to see manage the list of related jobs.
|
100
|
+
|
101
|
+
For example, you might create a job to send a reminder a week after a user is created, and relate this new job to that user.
|
102
|
+
By associating it with the `ActiveRecord` object, you can more easily manage this reminder, such as canceling it if they close their account.
|
103
|
+
|
104
|
+
When using `ActiveRecord` integration in Rails, there is a generator for the migration to create the tables for saving scheduled jobs:
|
105
|
+
```
|
106
|
+
bundle exec rails generate say_when:migration
|
107
|
+
```
|
108
|
+
|
109
|
+
The resulting migration assumes the scheduled jobs will use a integer based id column, please update the default migration if this is not the case in your system:
|
110
|
+
```ruby
|
111
|
+
# change this to string or other type as needed
|
112
|
+
t.integer :scheduled_id
|
113
|
+
```
|
114
|
+
|
115
|
+
## Pollers
|
116
|
+
|
117
|
+
The `SimplePoller` does what you would expect; when you run it, it starts up a loop of checking for jobs to run, sleeping, and then checking again.
|
118
|
+
|
119
|
+
It can be executed from the rake task:
|
120
|
+
```
|
121
|
+
bundle exec rake say_when:start
|
122
|
+
```
|
123
|
+
|
124
|
+
But that isn't doing much except loading the environment then this:
|
125
|
+
```ruby
|
126
|
+
require 'say_when'
|
127
|
+
require 'say_when/poller/simple_poller'
|
128
|
+
|
129
|
+
SayWhen::Poller::SimplePoller.start
|
130
|
+
```
|
131
|
+
|
132
|
+
For my own purposes, I use things like `daemontools` and `god` to daemonize, so this has been enough for me, but it would not be hard to write a command line script for it.
|
133
|
+
|
134
|
+
Most of the time I am also running a job processor, either `shoryuken` or `sidekiq`, and I would prefer to piggyback on that same process instead of starting up another. Since both of those use Celluloid (or did, Sidekiq no longer does), I also created a Celluloid actor class that can be added to the celluloid based job process via hooks in their startup.
|
135
|
+
|
136
|
+
For Shoryuken, add this to your initializer (probably `config/initializers/shoryuken.rb`):
|
137
|
+
```ruby
|
138
|
+
require 'say_when/poller/celluloid_poller'
|
139
|
+
|
140
|
+
Shoryuken.on_start do
|
141
|
+
# check for new jobs to run every 5 seconds
|
142
|
+
SayWhen::Poller::CelluloidPoller.supervise_as :say_when, 5
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
For Sidekiq, there is a slightly different syntax, but basically the same idea
|
147
|
+
(via https://github.com/mperham/sidekiq/wiki/Deployment#events):
|
148
|
+
```ruby
|
149
|
+
require 'say_when/poller/celluloid_poller'
|
150
|
+
|
151
|
+
Sidekiq.configure_server do |config|
|
152
|
+
config.on(:startup) do
|
153
|
+
SayWhen::Poller::CelluloidPoller.supervise_as :say_when, 5
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
24
157
|
|
25
158
|
## Contributing
|
26
159
|
|
data/Rakefile
CHANGED
data/lib/say_when.rb
CHANGED
@@ -1,32 +1,47 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'active_support'
|
3
|
+
require 'active_support/all'
|
4
4
|
|
5
|
-
require
|
6
|
-
require 'say_when/
|
5
|
+
require 'say_when/version'
|
6
|
+
require 'say_when/configuration'
|
7
|
+
require 'say_when/utils'
|
7
8
|
require 'say_when/cron_expression'
|
8
|
-
require 'say_when/processor/base'
|
9
|
-
require 'say_when/processor/simple'
|
10
9
|
require 'say_when/scheduler'
|
11
10
|
|
12
|
-
require 'say_when/processor/active_messaging' if defined?(::ActiveMessaging)
|
13
|
-
require 'say_when/processor/shoryuken' if defined?(::Shoryuken)
|
14
|
-
require 'say_when/storage/active_record/job' if defined?(::ActiveRecord)
|
15
11
|
require 'say_when/railtie' if defined?(Rails)
|
16
12
|
|
17
13
|
module SayWhen
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
if defined?(Rails.logger) && Rails.logger
|
25
|
-
@@logger = Rails.logger
|
14
|
+
class << self
|
15
|
+
def logger
|
16
|
+
@logger ||= if defined?(Rails)
|
17
|
+
Rails.logger
|
18
|
+
else
|
19
|
+
Logger.new(STDOUT)
|
26
20
|
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger=(l)
|
24
|
+
@logger = l
|
25
|
+
end
|
26
|
+
|
27
|
+
def options
|
28
|
+
@options ||= SayWhen::Configuration.default_options
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure(opts = {})
|
32
|
+
@lock ||= Mutex.new
|
33
|
+
options.merge(opts)
|
34
|
+
yield options if block_given?
|
35
|
+
end
|
36
|
+
|
37
|
+
def scheduler
|
38
|
+
return @scheduler if defined?(@scheduler) && @scheduler
|
39
|
+
@lock.synchronize { @scheduler = SayWhen::Scheduler.new }
|
40
|
+
@scheduler
|
41
|
+
end
|
27
42
|
|
28
|
-
|
43
|
+
def schedule(job)
|
44
|
+
scheduler.schedule(job)
|
29
45
|
end
|
30
|
-
@@logger
|
31
46
|
end
|
32
47
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module SayWhen
|
5
|
+
class Configuration
|
6
|
+
def self.default_options
|
7
|
+
{}.tap do |defaults|
|
8
|
+
defaults[:processor_strategy] = :simple
|
9
|
+
defaults[:storage_strategy] = :memory
|
10
|
+
defaults[:tick_length] = (ENV['SAY_WHEN_TICK_LENGTH'] || '5').to_i
|
11
|
+
defaults[:queue] = ENV['SAY_WHEN_QUEUE'] || 'default'
|
12
|
+
defaults[:reset_acquired_length] = (ENV['SAY_WHEN_RESET_ACQUIRED_LENGTH'] || '3600').to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,14 +3,13 @@
|
|
3
3
|
require 'date'
|
4
4
|
|
5
5
|
module SayWhen
|
6
|
-
|
7
6
|
# Based on the extended cron capabilties
|
8
|
-
# http://
|
7
|
+
# http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-06.html
|
9
8
|
class CronExpression
|
10
9
|
attr_reader :expression
|
11
10
|
attr_accessor :time_zone, :seconds, :minutes, :hours, :days_of_month, :months, :days_of_week, :years
|
12
11
|
|
13
|
-
def initialize(expression, time_zone=nil)
|
12
|
+
def initialize(expression = {}, time_zone = nil)
|
14
13
|
if expression.is_a?(Hash)
|
15
14
|
opts = expression
|
16
15
|
|
@@ -28,19 +27,14 @@ module SayWhen
|
|
28
27
|
"#{opts[:seconds]} #{opts[:minutes]} #{opts[:hours]} #{opts[:days_of_month]} #{opts[:months]} #{opts[:days_of_week]} #{opts[:years]}"
|
29
28
|
end
|
30
29
|
|
31
|
-
|
32
|
-
opts[:time_zone]
|
33
|
-
else
|
34
|
-
Time.zone.nil? ? "UTC" : Time.zone.name
|
35
|
-
end
|
36
|
-
|
30
|
+
@time_zone = opts[:time_zone]
|
37
31
|
else
|
38
32
|
@expression = expression
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
33
|
+
end
|
34
|
+
|
35
|
+
@time_zone ||= time_zone
|
36
|
+
if @time_zone.blank?
|
37
|
+
@time_zone = Time.zone.try(:name) || "UTC"
|
44
38
|
end
|
45
39
|
|
46
40
|
parse
|
@@ -122,7 +116,6 @@ module SayWhen
|
|
122
116
|
[before, false]
|
123
117
|
end
|
124
118
|
|
125
|
-
|
126
119
|
end
|
127
120
|
|
128
121
|
class CronValue
|
@@ -154,19 +147,24 @@ module SayWhen
|
|
154
147
|
values = []
|
155
148
|
case val
|
156
149
|
#check for a '/' for increments
|
157
|
-
when /(
|
150
|
+
when /(.+)\/(\d+)/
|
151
|
+
(( $1 == "*") ? min : $1.to_i).step(max, $2.to_i) { |x| values << x }
|
158
152
|
|
159
153
|
#check for ',' for list of values
|
160
|
-
when /(\d+)(,\d+)+/
|
154
|
+
when /(\d+)(,\d+)+/
|
155
|
+
values = val.split(',').map{ |v| v.to_i }.sort
|
161
156
|
|
162
157
|
#check for '-' for range of values
|
163
|
-
when /(\d+)-(\d+)/
|
158
|
+
when /(\d+)-(\d+)/
|
159
|
+
values = (($1.to_i)..($2.to_i)).to_a
|
164
160
|
|
165
161
|
#check for '*' for all values between min and max
|
166
|
-
when /^(\*)$/
|
162
|
+
when /^(\*)$/
|
163
|
+
values = (min..max).to_a
|
167
164
|
|
168
165
|
#lastly, should just be a number
|
169
|
-
when /^(\d+)$/
|
166
|
+
when /^(\d+)$/
|
167
|
+
values << $1.to_i
|
170
168
|
|
171
169
|
#if nothing else, leave values as []
|
172
170
|
else values = []
|
@@ -535,7 +533,7 @@ module SayWhen
|
|
535
533
|
|
536
534
|
class YearsCronValue < CronValue
|
537
535
|
def initialize(exp)
|
538
|
-
super(:year, 1970,
|
536
|
+
super(:year, 1970, (Date.today.year + 100), exp)
|
539
537
|
end
|
540
538
|
|
541
539
|
def next(date)
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'say_when/utils'
|
4
|
+
|
5
|
+
module SayWhen
|
6
|
+
module Poller
|
7
|
+
module BasePoller
|
8
|
+
def self.included(mod)
|
9
|
+
mod.include(SayWhen::Utils)
|
10
|
+
attr_accessor :reset_next_at
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
end
|
18
|
+
|
19
|
+
def reset_acquired
|
20
|
+
time_now = Time.now
|
21
|
+
self.reset_next_at ||= time_now
|
22
|
+
|
23
|
+
if reset_acquired_length > 0 && reset_next_at <= time_now
|
24
|
+
self.reset_next_at = time_now + reset_acquired_length
|
25
|
+
logger.debug "SayWhen:: reset acquired at #{time_now}, try again at #{reset_next_at}"
|
26
|
+
storage.reset_acquired(reset_acquired_length)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def job_error(msg, job, ex)
|
31
|
+
job_msg = job && " job:'#{job.inspect}'"
|
32
|
+
logger.error "#{self.class.name} #{msg}#{job_msg}: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
|
33
|
+
release(job)
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_jobs
|
37
|
+
reset_acquired
|
38
|
+
time_now = Time.now
|
39
|
+
while job = acquire(time_now)
|
40
|
+
process(job, time_now)
|
41
|
+
time_now = Time.now
|
42
|
+
end
|
43
|
+
rescue StandardError => ex
|
44
|
+
job_error("Error!", job, ex)
|
45
|
+
tick(error_tick_length)
|
46
|
+
rescue Interrupt => ex
|
47
|
+
job_error("Interrupt!", job, ex)
|
48
|
+
raise ex
|
49
|
+
rescue Exception => ex
|
50
|
+
job_error("Exception!", job, ex)
|
51
|
+
raise ex
|
52
|
+
end
|
53
|
+
|
54
|
+
def acquire(time_now)
|
55
|
+
logger.debug "SayWhen:: Looking for job that should be ready to fire before #{time_now}"
|
56
|
+
if job = self.storage.acquire_next(time_now)
|
57
|
+
logger.debug "SayWhen:: got a job: #{job.inspect}"
|
58
|
+
else
|
59
|
+
logger.debug "SayWhen:: no jobs to acquire"
|
60
|
+
end
|
61
|
+
job
|
62
|
+
end
|
63
|
+
|
64
|
+
def process(job, time_now)
|
65
|
+
# delegate processing the trigger to the processor
|
66
|
+
processor.process(job)
|
67
|
+
logger.debug "SayWhen:: job processed: #{job.inspect}"
|
68
|
+
|
69
|
+
# this should update next fire at, and put back in list of scheduled jobs
|
70
|
+
storage.fired(job, time_now)
|
71
|
+
logger.debug "SayWhen:: job fired: #{job.inspect}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def release(job)
|
75
|
+
logger.info "SayWhen::Scheduler release: #{job.inspect}"
|
76
|
+
job.release if job
|
77
|
+
end
|
78
|
+
|
79
|
+
def tick(t = tick_length)
|
80
|
+
sleep(t.to_f)
|
81
|
+
end
|
82
|
+
|
83
|
+
def tick_length
|
84
|
+
@tick_length ||= SayWhen.options[:tick_length].to_f
|
85
|
+
end
|
86
|
+
|
87
|
+
def error_tick_length
|
88
|
+
@error_tick_length ||= SayWhen.options[:error_tick_length].to_f || tick_length
|
89
|
+
end
|
90
|
+
|
91
|
+
def reset_acquired_length
|
92
|
+
@reset_acquired_length ||= SayWhen.options[:reset_acquired_length].to_f
|
93
|
+
end
|
94
|
+
|
95
|
+
def processor
|
96
|
+
@processor ||= load_strategy(:processor, SayWhen.options[:processor_strategy])
|
97
|
+
end
|
98
|
+
|
99
|
+
def storage
|
100
|
+
@storage ||= load_strategy(:storage, SayWhen.options[:storage_strategy])
|
101
|
+
end
|
102
|
+
|
103
|
+
def logger
|
104
|
+
SayWhen.logger
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|