resque-scheduler 2.1.0 → 2.1.1
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.
Potentially problematic release.
This version of resque-scheduler might be problematic. Click here for more details.
- data/.gitignore +2 -0
- data/AUTHORS.md +2 -0
- data/README.md +8 -1
- data/lib/resque/scheduler.rb +4 -1
- data/lib/resque/scheduler_locking.rb +1 -1
- data/lib/resque_scheduler.rb +34 -19
- data/lib/resque_scheduler/server.rb +24 -1
- data/lib/resque_scheduler/server/views/requeue-params.erb +23 -0
- data/lib/resque_scheduler/server/views/scheduler.erb +2 -2
- data/lib/resque_scheduler/version.rb +1 -1
- data/resque-scheduler.gemspec +2 -2
- data/test/resque-web_test.rb +84 -0
- data/test/scheduler_test.rb +2 -2
- metadata +9 -14
data/AUTHORS.md
CHANGED
@@ -21,6 +21,7 @@ Resque Scheduler authors
|
|
21
21
|
- Denis Yagofarov
|
22
22
|
- Evan Tahler
|
23
23
|
- Giovanni Cappellotto
|
24
|
+
- Harry Lascelles
|
24
25
|
- Henrik Nyh
|
25
26
|
- James Le Cuirot
|
26
27
|
- John Crepezzi
|
@@ -47,6 +48,7 @@ Resque Scheduler authors
|
|
47
48
|
- Ryan Biesemeyer
|
48
49
|
- Ryan Carver
|
49
50
|
- Sebastian Kippe
|
51
|
+
- Spring MC
|
50
52
|
- Tim Liner
|
51
53
|
- Tony Lewis
|
52
54
|
- V Sreekanth
|
data/README.md
CHANGED
@@ -319,6 +319,13 @@ scheduled jobs, however, will not fire upon recovery of the scheduler process.
|
|
319
319
|
Think of scheduled (recurring) jobs as cron jobs - if you stop cron, it doesn't fire
|
320
320
|
missed jobs once it starts back up.
|
321
321
|
|
322
|
+
You might want to share a redis instance amongst multiple Rails applications with different
|
323
|
+
scheduler with different config yaml files. If this is the case, normally, only one will ever
|
324
|
+
run, leading to undesired behaviour. To allow different scheduler configs run at the same time
|
325
|
+
on one redis, you can either namespace your redis connections, or supply an environment variable
|
326
|
+
to split the shared lock key resque-scheduler uses thus:
|
327
|
+
|
328
|
+
RESQUE_SCHEDULER_MASTER_LOCK_PREFIX=MyApp: rake resque:scheduler
|
322
329
|
|
323
330
|
### resque-web Additions
|
324
331
|
|
@@ -328,7 +335,7 @@ the delayed queue.
|
|
328
335
|
|
329
336
|
The Schedule tab:
|
330
337
|
|
331
|
-

|
332
339
|
|
333
340
|
The Delayed tab:
|
334
341
|
|
data/lib/resque/scheduler.rb
CHANGED
@@ -44,6 +44,7 @@ module Resque
|
|
44
44
|
# Schedule all jobs and continually look for delayed jobs (never returns)
|
45
45
|
def run
|
46
46
|
$0 = "resque-scheduler: Starting"
|
47
|
+
|
47
48
|
# trap signals
|
48
49
|
register_signal_handlers
|
49
50
|
|
@@ -307,10 +308,12 @@ module Resque
|
|
307
308
|
true
|
308
309
|
end
|
309
310
|
|
310
|
-
# Sets the shutdown flag, exits if sleeping
|
311
|
+
# Sets the shutdown flag, clean schedules and exits if sleeping
|
311
312
|
def shutdown
|
312
313
|
@shutdown = true
|
314
|
+
|
313
315
|
if @sleeping
|
316
|
+
Resque.clean_schedules
|
314
317
|
Thread.new { release_master_lock! }
|
315
318
|
exit
|
316
319
|
end
|
data/lib/resque_scheduler.rb
CHANGED
@@ -25,7 +25,7 @@ module ResqueScheduler
|
|
25
25
|
# is used implicitly as "class" argument - in the "MakeTea" example,
|
26
26
|
# "MakeTea" is used both as job name and resque worker class.
|
27
27
|
#
|
28
|
-
# Any jobs that were in the old schedule, but are not
|
28
|
+
# Any jobs that were in the old schedule, but are not
|
29
29
|
# present in the new schedule, will be removed.
|
30
30
|
#
|
31
31
|
# :cron can be any cron scheduling string
|
@@ -46,23 +46,27 @@ module ResqueScheduler
|
|
46
46
|
# params is an array, each element in the array is passed as a separate
|
47
47
|
# param, otherwise params is passed in as the only parameter to perform.
|
48
48
|
def schedule=(schedule_hash)
|
49
|
+
# clean the schedules as it exists in redis
|
50
|
+
clean_schedules
|
51
|
+
|
49
52
|
schedule_hash = prepare_schedule(schedule_hash)
|
50
53
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
set_schedule(name, job_spec)
|
55
|
-
end
|
56
|
-
(schedule.keys - schedule_hash.keys.map(&:to_s)).each do |name|
|
57
|
-
remove_schedule(name)
|
58
|
-
end
|
54
|
+
# store all schedules in redis, so we can retrieve them back everywhere.
|
55
|
+
schedule_hash.each do |name, job_spec|
|
56
|
+
set_schedule(name, job_spec)
|
59
57
|
end
|
60
|
-
|
58
|
+
|
59
|
+
# ensure only return the successfully saved data!
|
60
|
+
reload_schedule!
|
61
61
|
end
|
62
62
|
|
63
63
|
# Returns the schedule hash
|
64
64
|
def schedule
|
65
|
-
@schedule ||=
|
65
|
+
@schedule ||= get_schedules
|
66
|
+
if @schedule.nil?
|
67
|
+
return {}
|
68
|
+
end
|
69
|
+
@schedule
|
66
70
|
end
|
67
71
|
|
68
72
|
# reloads the schedule from redis
|
@@ -70,17 +74,28 @@ module ResqueScheduler
|
|
70
74
|
@schedule = get_schedules
|
71
75
|
end
|
72
76
|
|
73
|
-
# gets the
|
77
|
+
# gets the schedules as it exists in redis
|
74
78
|
def get_schedules
|
79
|
+
unless redis.exists(:schedules)
|
80
|
+
return nil
|
81
|
+
end
|
82
|
+
|
83
|
+
redis.hgetall(:schedules).tap do |h|
|
84
|
+
h.each do |name, config|
|
85
|
+
h[name] = decode(config)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# clean the schedules as it exists in redis, useful for first setup?
|
91
|
+
def clean_schedules
|
75
92
|
if redis.exists(:schedules)
|
76
|
-
redis.
|
77
|
-
|
78
|
-
h[name] = decode(config)
|
79
|
-
end
|
93
|
+
redis.hkeys(:schedules).each do |key|
|
94
|
+
remove_schedule(key)
|
80
95
|
end
|
81
|
-
else
|
82
|
-
nil
|
83
96
|
end
|
97
|
+
@schedule = nil
|
98
|
+
true
|
84
99
|
end
|
85
100
|
|
86
101
|
# Create or update a schedule with the provided name and configuration.
|
@@ -314,7 +329,7 @@ module ResqueScheduler
|
|
314
329
|
redis.unwatch
|
315
330
|
end
|
316
331
|
end
|
317
|
-
|
332
|
+
|
318
333
|
def validate_job!(klass)
|
319
334
|
if klass.to_s.empty?
|
320
335
|
raise Resque::NoClassError.new("Jobs must be given a class.")
|
@@ -27,7 +27,30 @@ module ResqueScheduler
|
|
27
27
|
end
|
28
28
|
|
29
29
|
post "/schedule/requeue" do
|
30
|
-
|
30
|
+
@job_name = params['job_name'] || params[:job_name]
|
31
|
+
config = Resque.schedule[@job_name]
|
32
|
+
@parameters = config['parameters'] || config[:parameters]
|
33
|
+
if @parameters
|
34
|
+
erb File.read(File.join(File.dirname(__FILE__), 'server/views/requeue-params.erb'))
|
35
|
+
else
|
36
|
+
Resque::Scheduler.enqueue_from_config(config)
|
37
|
+
redirect u("/overview")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
post "/schedule/requeue_with_params" do
|
42
|
+
job_name = params['job_name'] || params[:job_name]
|
43
|
+
config = Resque.schedule[job_name]
|
44
|
+
# Build args hash from post data (removing the job name)
|
45
|
+
submitted_args = params.reject {|key, value| key == 'job_name' || key == :job_name}
|
46
|
+
|
47
|
+
# Merge constructed args hash with existing args hash for
|
48
|
+
# the job, if it exists
|
49
|
+
config_args = config['args'] || config[:args] || {}
|
50
|
+
config_args = config_args.merge(submitted_args)
|
51
|
+
|
52
|
+
# Insert the args hash into config and queue the resque job
|
53
|
+
config = config.merge({'args' => config_args})
|
31
54
|
Resque::Scheduler.enqueue_from_config(config)
|
32
55
|
redirect u("/overview")
|
33
56
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h1><%= @job_name %></h1>
|
2
|
+
|
3
|
+
<p class='intro'>
|
4
|
+
This job requires parameters:
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<form style="float:left" action="<%= u "/schedule/requeue_with_params" %>" method="post">
|
8
|
+
<table>
|
9
|
+
<% @parameters.each do |key, value| %>
|
10
|
+
<% value ||= {} %>
|
11
|
+
<tr>
|
12
|
+
<td>
|
13
|
+
<%= key %>
|
14
|
+
<% if value['description'] || value[:description] %>
|
15
|
+
<span style="border-bottom:1px dotted;" title="<%=value ['description'] || value[:description] %>">(?)</span>
|
16
|
+
<% end %>:
|
17
|
+
</td>
|
18
|
+
<td><input type="text" name="<%= key %>" value="<%= value['default'] || value[:default] %>"></td>
|
19
|
+
<% end %>
|
20
|
+
</table>
|
21
|
+
<input type="hidden" name="job_name" value="<%= @job_name %>">
|
22
|
+
<input type="submit" value="Queue now">
|
23
|
+
</form>
|
@@ -27,10 +27,10 @@
|
|
27
27
|
</td>
|
28
28
|
<td><%= h name %></td>
|
29
29
|
<td><%= h config['description'] %></td>
|
30
|
-
<td style="white-space:nowrap"><%= if !config['every'].nil?
|
30
|
+
<td style="white-space:nowrap"><%= if !config['every'].nil?
|
31
31
|
h('every: ' + (config['every'].is_a?(Array) ? config['every'].join(", ") : config['every'].to_s ))
|
32
32
|
elsif !config['cron'].nil?
|
33
|
-
h('cron: ' + config['cron'].to_s)
|
33
|
+
h('cron: ' + config['cron'].to_s)
|
34
34
|
else
|
35
35
|
'Not currently scheduled'
|
36
36
|
end %></td>
|
data/resque-scheduler.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency 'json' if RUBY_VERSION < '1.9'
|
27
27
|
spec.add_development_dependency 'rubocop' unless RUBY_VERSION < '1.9'
|
28
28
|
|
29
|
-
spec.add_runtime_dependency 'redis', '>=
|
29
|
+
spec.add_runtime_dependency 'redis', '>= 3.0.0'
|
30
30
|
spec.add_runtime_dependency 'resque', ['>= 1.20.0', '< 1.25']
|
31
|
-
spec.add_runtime_dependency 'rufus-scheduler', '
|
31
|
+
spec.add_runtime_dependency 'rufus-scheduler', '~> 2.0'
|
32
32
|
end
|
data/test/resque-web_test.rb
CHANGED
@@ -30,3 +30,87 @@ context "on GET to /delayed" do
|
|
30
30
|
|
31
31
|
should_respond_with_success
|
32
32
|
end
|
33
|
+
|
34
|
+
def resque_schedule
|
35
|
+
{
|
36
|
+
'job_without_params' => {
|
37
|
+
'cron' => "* * * * *",
|
38
|
+
'class' => 'JobWithoutParams',
|
39
|
+
'args' => {"host" => 'localhost'},
|
40
|
+
'rails_env' => 'production'},
|
41
|
+
'job_with_params' => {
|
42
|
+
'cron' => "* * * * *",
|
43
|
+
'class' => 'JobWithParams',
|
44
|
+
'args' => {"host" => 'localhost'},
|
45
|
+
'parameters' => {
|
46
|
+
'log_level' => {
|
47
|
+
'description' => 'The level of logging',
|
48
|
+
'default' => 'warn'
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
context "POST /schedule/requeue" do
|
56
|
+
setup do
|
57
|
+
Resque.schedule = resque_schedule
|
58
|
+
Resque::Scheduler.load_schedule!
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'job without params' do
|
62
|
+
# Regular jobs without params should redirect to /overview
|
63
|
+
job_name = 'job_without_params'
|
64
|
+
Resque::Scheduler.stubs(:enqueue_from_config).once.with(Resque.schedule[job_name])
|
65
|
+
|
66
|
+
post '/schedule/requeue', {'job_name' => job_name}
|
67
|
+
follow_redirect!
|
68
|
+
assert_equal "http://example.org/overview", last_request.url
|
69
|
+
assert last_response.ok?
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'job with params' do
|
73
|
+
# If a job has params defined,
|
74
|
+
# it should render the template with a form for the job params
|
75
|
+
job_name = 'job_with_params'
|
76
|
+
post '/schedule/requeue', {'job_name' => job_name}
|
77
|
+
|
78
|
+
assert last_response.ok?, last_response.errors
|
79
|
+
assert last_response.body.include?("This job requires parameters")
|
80
|
+
assert last_response.body.include?("<input type=\"hidden\" name=\"job_name\" value=\"#{job_name}\">")
|
81
|
+
|
82
|
+
Resque.schedule[job_name]['parameters'].each do |param_name, param_config|
|
83
|
+
assert last_response.body.include?(
|
84
|
+
"<span style=\"border-bottom:1px dotted;\" title=\"#{param_config['description']}\">(?)</span>")
|
85
|
+
assert last_response.body.include?(
|
86
|
+
"<input type=\"text\" name=\"log_level\" value=\"#{param_config['default']}\">")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "POST /schedule/requeue_with_params" do
|
92
|
+
setup do
|
93
|
+
Resque.schedule = resque_schedule
|
94
|
+
Resque::Scheduler.load_schedule!
|
95
|
+
end
|
96
|
+
|
97
|
+
test 'job with params' do
|
98
|
+
job_name = 'job_with_params'
|
99
|
+
log_level = 'error'
|
100
|
+
|
101
|
+
job_config = Resque.schedule[job_name]
|
102
|
+
args = job_config['args'].merge({'log_level' => log_level})
|
103
|
+
job_config = job_config.merge({'args' => args})
|
104
|
+
|
105
|
+
Resque::Scheduler.stubs(:enqueue_from_config).once.with(job_config)
|
106
|
+
|
107
|
+
post '/schedule/requeue_with_params', {
|
108
|
+
'job_name' => job_name,
|
109
|
+
'log_level' => log_level
|
110
|
+
}
|
111
|
+
follow_redirect!
|
112
|
+
assert_equal "http://example.org/overview", last_request.url
|
113
|
+
|
114
|
+
assert last_response.ok?, last_response.errors
|
115
|
+
end
|
116
|
+
end
|
data/test/scheduler_test.rb
CHANGED
@@ -46,7 +46,7 @@ context "Resque::Scheduler" do
|
|
46
46
|
Resque::Scheduler.load_schedule!
|
47
47
|
|
48
48
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
49
|
-
assert Resque::Scheduler.scheduled_jobs.include?(
|
49
|
+
assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job')
|
50
50
|
end
|
51
51
|
|
52
52
|
test "can reload schedule" do
|
@@ -191,7 +191,7 @@ context "Resque::Scheduler" do
|
|
191
191
|
assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75"},
|
192
192
|
Resque.decode(Resque.redis.hget(:schedules, "my_ivar_job")))
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
test "schedule= removes schedules not present in the given schedule argument" do
|
196
196
|
Resque::Scheduler.dynamic = true
|
197
197
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ! '>='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 3.0.0
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 3.0.0
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: resque
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,17 +134,17 @@ dependencies:
|
|
134
134
|
requirement: !ruby/object:Gem::Requirement
|
135
135
|
none: false
|
136
136
|
requirements:
|
137
|
-
- -
|
137
|
+
- - ~>
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version: '0'
|
139
|
+
version: '2.0'
|
140
140
|
type: :runtime
|
141
141
|
prerelease: false
|
142
142
|
version_requirements: !ruby/object:Gem::Requirement
|
143
143
|
none: false
|
144
144
|
requirements:
|
145
|
-
- -
|
145
|
+
- - ~>
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: '0'
|
147
|
+
version: '2.0'
|
148
148
|
description: ! "Light weight job scheduling on top of Resque.\n Adds methods enqueue_at/enqueue_in
|
149
149
|
to schedule jobs in the future.\n Also supports queueing jobs on a fixed, cron-like
|
150
150
|
schedule."
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- lib/resque_scheduler/server.rb
|
177
177
|
- lib/resque_scheduler/server/views/delayed.erb
|
178
178
|
- lib/resque_scheduler/server/views/delayed_timestamp.erb
|
179
|
+
- lib/resque_scheduler/server/views/requeue-params.erb
|
179
180
|
- lib/resque_scheduler/server/views/scheduler.erb
|
180
181
|
- lib/resque_scheduler/tasks.rb
|
181
182
|
- lib/resque_scheduler/version.rb
|
@@ -204,18 +205,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
204
205
|
- - ! '>='
|
205
206
|
- !ruby/object:Gem::Version
|
206
207
|
version: '0'
|
207
|
-
segments:
|
208
|
-
- 0
|
209
|
-
hash: 2224918234097590124
|
210
208
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
211
209
|
none: false
|
212
210
|
requirements:
|
213
211
|
- - ! '>='
|
214
212
|
- !ruby/object:Gem::Version
|
215
213
|
version: '0'
|
216
|
-
segments:
|
217
|
-
- 0
|
218
|
-
hash: 2224918234097590124
|
219
214
|
requirements: []
|
220
215
|
rubyforge_project:
|
221
216
|
rubygems_version: 1.8.23
|