resque-scheduler 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of resque-scheduler might be problematic. Click here for more details.

data/.gitignore CHANGED
@@ -4,3 +4,5 @@ pkg
4
4
  nbproject
5
5
  Gemfile.lock
6
6
  .rvmrc
7
+ *.swp
8
+
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
- ![The Schedule Tab](http://img.skitch.com/20100111-km2f5gmtpbq23enpujbruj6mgk.png)
338
+ ![The Schedule Tab](https://f.cloud.github.com/assets/45143/1178456/c99e5568-21b0-11e3-8c57-e1305d0ee8ef.png)
332
339
 
333
340
  The Delayed tab:
334
341
 
@@ -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
@@ -80,7 +80,7 @@ module Resque
80
80
  end
81
81
 
82
82
  def master_lock_key
83
- :resque_scheduler_master_lock
83
+ "#{ENV['RESQUE_SCHEDULER_MASTER_LOCK_PREFIX'] || ''}resque_scheduler_master_lock".to_sym
84
84
  end
85
85
 
86
86
  def redis_master_version
@@ -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
- if Resque::Scheduler.dynamic
52
- reload_schedule!
53
- schedule_hash.each do |name, job_spec|
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
- @schedule = schedule_hash
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 schedule as it exists in redis
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.hgetall(:schedules).tap do |h|
77
- h.each do |name, config|
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
- config = Resque.schedule[params['job_name']]
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>
@@ -1,3 +1,3 @@
1
1
  module ResqueScheduler
2
- VERSION = '2.1.0'
2
+ VERSION = '2.1.1'
3
3
  end
@@ -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', '>= 2.0.1'
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', '>= 0'
31
+ spec.add_runtime_dependency 'rufus-scheduler', '~> 2.0'
32
32
  end
@@ -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
@@ -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?(:some_ivar_job)
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.0
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-09-20 00:00:00.000000000 Z
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: 2.0.1
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: 2.0.1
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