brianjlandau-resque-scheduler 1.10.2 → 1.10.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -140,20 +140,11 @@ environment variable, the job won't be loaded.
140
140
 
141
141
  ### Dynamic Schedules
142
142
 
143
- If you need schedules that are defined based on user interactions inside of your application, this can be completed by loading it initially wherever you configure Resque and defining `Resque.reload_schedule!`:
143
+ If needed you can also have schedules that are dynamically defined and updated inside of your application. This can be completed by loading the schedule initially wherever you configure Resque and setting `Resque::Scheduler.dynamic` to `true`. Then subsequently updating the "`schedule`" key in redis (namespaced to the Resque namespace) with a JSON encoded version of the schedule hash will cause the schedule to be updated.
144
144
 
145
- module Resque
146
- def self.reload_schedule!
147
- self.schedule = MyScheduleModel.all.inject({}) {|schedule_hash, record|
148
- schedule_hash[record.name.to_sym] = record.attributes.select{|key, value| key != 'name' }
149
- schedule_hash
150
- }
151
- end
152
- end
153
-
154
- Resque.reload_schedule!
145
+ When the scheduler loops it will look for differences between the existing schedule and the current schedule in redis. If there are differences it will make the necessary changes to the running schedule.
155
146
 
156
- To have the scheduler reload the schedule you just send it the `USR2` signal.
147
+ To force the scheduler to reload the schedule you just send it the `USR2` signal.
157
148
 
158
149
  ### Support for customized Job classes
159
150
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{brianjlandau-resque-scheduler}
8
- s.version = "1.10.2"
8
+ s.version = "1.10.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben VandenBos", "Brian Landau"]
12
- s.date = %q{2010-10-18}
12
+ s.date = %q{2010-10-20}
13
13
  s.description = %q{Light weight job scheduling on top of Resque.
14
14
  Adds methods enqueue_at/enqueue_in to schedule jobs in the future.
15
15
  Also supports queueing jobs on a fixed, cron-like schedule.}
@@ -14,6 +14,14 @@ module Resque
14
14
 
15
15
  # If set, produces no output
16
16
  attr_accessor :mute
17
+
18
+ # If set, will try to update the schulde in the loop
19
+ attr_accessor :dynamic
20
+
21
+ # the Rufus::Scheduler jobs that are scheduled
22
+ def scheduled_jobs
23
+ @@scheduled_jobs
24
+ end
17
25
 
18
26
  # Schedule all jobs and continually look for delayed jobs (never returns)
19
27
  def run
@@ -27,6 +35,7 @@ module Resque
27
35
  # Now start the scheduling part of the loop.
28
36
  loop do
29
37
  handle_delayed_items
38
+ update_schedule if dynamic
30
39
  poll_sleep
31
40
  end
32
41
 
@@ -53,22 +62,29 @@ module Resque
53
62
  # rufus scheduler instance
54
63
  def load_schedule!
55
64
  log! "Schedule empty! Set Resque.schedule" if Resque.schedule.empty?
56
-
65
+
66
+ @@scheduled_jobs = {}
67
+
57
68
  Resque.schedule.each do |name, config|
58
- # If rails_env is set in the config, enforce ENV['RAILS_ENV'] as
59
- # required for the jobs to be scheduled. If rails_env is missing, the
60
- # job should be scheduled regardless of what ENV['RAILS_ENV'] is set
61
- # to.
62
- if config['rails_env'].nil? || rails_env_matches?(config)
63
- log! "Scheduling #{name} "
64
- if !config['cron'].nil? && config['cron'].length > 0
65
- rufus_scheduler.cron config['cron'] do
66
- log! "queuing #{config['class']} (#{name})"
67
- enqueue_from_config(config)
68
- end
69
- else
70
- log! "no cron found for #{config['class']} (#{name}) - skipping"
69
+ load_schedule_job(name, config)
70
+ end
71
+ end
72
+
73
+ # Loads a job schedule into the Rufus::Scheduler and stores it in @@scheduled_jobs
74
+ def load_schedule_job(name, config)
75
+ # If rails_env is set in the config, enforce ENV['RAILS_ENV'] as
76
+ # required for the jobs to be scheduled. If rails_env is missing, the
77
+ # job should be scheduled regardless of what ENV['RAILS_ENV'] is set
78
+ # to.
79
+ if config['rails_env'].nil? || rails_env_matches?(config)
80
+ log! "Scheduling #{name} "
81
+ if !config['cron'].nil? && config['cron'].length > 0
82
+ @@scheduled_jobs[name] = rufus_scheduler.cron config['cron'] do
83
+ log! "queuing #{config['class']} (#{name})"
84
+ enqueue_from_config(config)
71
85
  end
86
+ else
87
+ log! "no cron found for #{config['class']} (#{name}) - skipping"
72
88
  end
73
89
  end
74
90
  end
@@ -150,6 +166,34 @@ module Resque
150
166
  Resque.reload_schedule!
151
167
  load_schedule!
152
168
  end
169
+
170
+ def update_schedule
171
+ schedule_from_redis = Resque.decode(Resque.redis.get(:schedule))
172
+ if !schedule_from_redis.nil? && !schedule_from_redis.empty? && schedule_from_redis != Resque.schedule
173
+ # unload schedules that no longer exist
174
+ (Resque.schedule.keys - schedule_from_redis.keys).each do |name|
175
+ unschedule_job(name)
176
+ end
177
+
178
+ # find changes and stop and reload or add new
179
+ schedule_from_redis.each do |name, config|
180
+ if (Resque.schedule[name].nil? || Resque.schedule[name].empty?) || (config != Resque.schedule[name])
181
+ unschedule_job(name)
182
+ load_schedule_job(name, config)
183
+ end
184
+ end
185
+
186
+ # load new schedule into Resque.schedule
187
+ Resque.schedule = schedule_from_redis
188
+ end
189
+ end
190
+
191
+ def unschedule_job(name)
192
+ if scheduled_jobs[name]
193
+ scheduled_jobs[name].unschedule
194
+ @@scheduled_jobs.delete(name)
195
+ end
196
+ end
153
197
 
154
198
  # Sleeps and returns true
155
199
  def poll_sleep
@@ -33,6 +33,11 @@ module ResqueScheduler
33
33
  def schedule
34
34
  @schedule ||= {}
35
35
  end
36
+
37
+ # reloads the schedule from redis
38
+ def reload_schedule!
39
+ @schedule = decode(redis.get(:schedule))
40
+ end
36
41
 
37
42
  # This method is nearly identical to +enqueue+ only it also
38
43
  # takes a timestamp which will be used to schedule the job
@@ -1,3 +1,3 @@
1
1
  module ResqueScheduler
2
- Version = '1.10.2'
2
+ Version = '1.10.3'
3
3
  end
@@ -1,11 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
- module ::Resque
4
- def self.reload_schedule!
5
- self.schedule = {:some_ivar_job2 => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}}
6
- end
7
- end
8
-
9
3
  class Resque::SchedulerTest < Test::Unit::TestCase
10
4
 
11
5
  class FakeJob
@@ -13,7 +7,9 @@ class Resque::SchedulerTest < Test::Unit::TestCase
13
7
  end
14
8
 
15
9
  def setup
10
+ Resque::Scheduler.mute = true
16
11
  Resque::Scheduler.clear_schedule!
12
+ Resque::Scheduler.send(:class_variable_set, :@@scheduled_jobs, {})
17
13
  end
18
14
 
19
15
  def test_enqueue_from_config_puts_stuff_in_the_resque_queue_without_class_loaded
@@ -76,19 +72,110 @@ class Resque::SchedulerTest < Test::Unit::TestCase
76
72
  Resque::Scheduler.load_schedule!
77
73
 
78
74
  assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
75
+ assert Resque::Scheduler.scheduled_jobs.include?(:some_ivar_job)
79
76
  end
80
77
 
81
78
  def test_can_reload_schedule
82
- Resque.schedule = {:some_ivar_job => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}}
79
+ Resque.schedule = {"some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}}
80
+ Resque.redis.set(:schedule, Resque.encode({
81
+ "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}
82
+ }))
83
+
83
84
  Resque::Scheduler.load_schedule!
84
85
 
85
86
  assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
87
+ assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job")
88
+
89
+ Resque.redis.set(:schedule, Resque.encode({
90
+ "some_ivar_job2" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}
91
+ }))
86
92
 
87
93
  Resque::Scheduler.reload_schedule!
88
94
 
89
95
  assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
90
96
 
91
- assert_equal '/tmp/2', Resque.schedule[:some_ivar_job2]["args"]
97
+ assert_equal '/tmp/2', Resque.schedule["some_ivar_job2"]["args"]
98
+ assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job2")
99
+ end
100
+
101
+ def test_load_schedule_job
102
+ Resque::Scheduler.load_schedule_job("some_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"})
103
+
104
+ assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
105
+ assert_equal(1, Resque::Scheduler.scheduled_jobs.size)
106
+ assert Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
107
+ end
108
+
109
+ def test_load_schedule_job_with_no_cron
110
+ Resque::Scheduler.load_schedule_job("some_ivar_job", {'class' => 'SomeIvarJob', 'args' => "/tmp"})
111
+
112
+ assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
113
+ assert_equal(0, Resque::Scheduler.scheduled_jobs.size)
114
+ assert !Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
115
+ end
116
+
117
+ def test_load_schedule_job_with_blank_cron
118
+ Resque::Scheduler.load_schedule_job("some_ivar_job", {'cron' => '', 'class' => 'SomeIvarJob', 'args' => "/tmp"})
119
+
120
+ assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
121
+ assert_equal(0, Resque::Scheduler.scheduled_jobs.size)
122
+ assert !Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
123
+ end
124
+
125
+ def test_update_schedule
126
+ Resque.schedule = {
127
+ "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"},
128
+ "another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"},
129
+ "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
130
+ }
131
+
132
+ Resque::Scheduler.load_schedule!
133
+
134
+ Resque.redis.set(:schedule, Resque.encode({
135
+ "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"},
136
+ "new_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"},
137
+ "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
138
+ }))
139
+
140
+ Resque::Scheduler.update_schedule
141
+
142
+ assert_equal(3, Resque::Scheduler.rufus_scheduler.all_jobs.size)
143
+ assert_equal(3, Resque::Scheduler.scheduled_jobs.size)
144
+ %w(some_ivar_job new_ivar_job stay_put_job).each do |job_name|
145
+ assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
146
+ assert Resque.schedule.keys.include?(job_name)
147
+ end
148
+ assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job")
149
+ assert !Resque.schedule.keys.include?("another_ivar_job")
150
+ end
151
+
152
+ def test_update_schedule_with_mocks
153
+ Resque.schedule = {
154
+ "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"},
155
+ "another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"},
156
+ "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
157
+ }
158
+
159
+ Resque::Scheduler.load_schedule!
160
+
161
+ Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["some_ivar_job"].job_id)
162
+ Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["another_ivar_job"].job_id)
163
+
164
+ Resque.redis.set(:schedule, Resque.encode({
165
+ "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"},
166
+ "new_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"},
167
+ "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
168
+ }))
169
+
170
+ Resque::Scheduler.update_schedule
171
+
172
+ assert_equal(3, Resque::Scheduler.scheduled_jobs.size)
173
+ %w(some_ivar_job new_ivar_job stay_put_job).each do |job_name|
174
+ assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
175
+ assert Resque.schedule.keys.include?(job_name)
176
+ end
177
+ assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job")
178
+ assert !Resque.schedule.keys.include?("another_ivar_job")
92
179
  end
93
180
 
94
181
  def test_adheres_to_lint
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brianjlandau-resque-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
4
+ hash: 57
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 10
9
- - 2
10
- version: 1.10.2
9
+ - 3
10
+ version: 1.10.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ben VandenBos
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-18 00:00:00 -04:00
19
+ date: 2010-10-20 00:00:00 -04:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency