resque-scheduler 1.9.10 → 2.0.0.a
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 +0 -3
- data/Gemfile +1 -2
- data/Gemfile.lock +52 -0
- data/HISTORY.md +3 -14
- data/README.markdown +98 -44
- data/Rakefile +3 -31
- data/lib/resque/scheduler.rb +98 -42
- data/lib/resque_scheduler.rb +48 -34
- data/lib/resque_scheduler/server.rb +8 -7
- data/lib/resque_scheduler/server/views/delayed.erb +3 -3
- data/lib/resque_scheduler/server/views/scheduler.erb +4 -4
- data/lib/resque_scheduler/tasks.rb +1 -1
- data/lib/resque_scheduler/version.rb +1 -1
- data/resque-scheduler.gemspec +23 -26
- data/test/delayed_queue_test.rb +5 -41
- data/test/redis-test.conf +1 -1
- data/test/resque-web_test.rb +2 -3
- data/test/scheduler_args_test.rb +1 -1
- data/test/scheduler_test.rb +159 -6
- data/test/test_helper.rb +8 -8
- metadata +121 -139
- checksums.yaml +0 -7
- data/.rubocop.yml +0 -120
- data/.travis.yml +0 -10
data/lib/resque_scheduler.rb
CHANGED
@@ -18,7 +18,7 @@ module ResqueScheduler
|
|
18
18
|
#
|
19
19
|
# :name can be anything and is used only to describe the scheduled job
|
20
20
|
# :cron can be any cron scheduling string :job can be any resque job class
|
21
|
-
# :every can be used in lieu of :cron. see rufus-scheduler's 'every' usage for
|
21
|
+
# :every can be used in lieu of :cron. see rufus-scheduler's 'every' usage for
|
22
22
|
# valid syntax. If :cron is present it will take precedence over :every.
|
23
23
|
# :class must be a resque worker class
|
24
24
|
# :args can be any yaml which will be converted to a ruby literal and passed
|
@@ -28,6 +28,11 @@ module ResqueScheduler
|
|
28
28
|
# an array, each element in the array is passed as a separate param,
|
29
29
|
# otherwise params is passed in as the only parameter to perform.
|
30
30
|
def schedule=(schedule_hash)
|
31
|
+
if Resque::Scheduler.dynamic
|
32
|
+
schedule_hash.each do |name, job_spec|
|
33
|
+
set_schedule(name, job_spec)
|
34
|
+
end
|
35
|
+
end
|
31
36
|
@schedule = schedule_hash
|
32
37
|
end
|
33
38
|
|
@@ -35,37 +40,60 @@ module ResqueScheduler
|
|
35
40
|
def schedule
|
36
41
|
@schedule ||= {}
|
37
42
|
end
|
43
|
+
|
44
|
+
# reloads the schedule from redis
|
45
|
+
def reload_schedule!
|
46
|
+
@schedule = get_schedules
|
47
|
+
end
|
48
|
+
|
49
|
+
# gets the schedule as it exists in redis
|
50
|
+
def get_schedules
|
51
|
+
if redis.exists(:schedules)
|
52
|
+
redis.hgetall(:schedules).tap do |h|
|
53
|
+
h.each do |name, config|
|
54
|
+
h[name] = decode(config)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# create or update a schedule with the provided name and configuration
|
63
|
+
def set_schedule(name, config)
|
64
|
+
existing_config = get_schedule(name)
|
65
|
+
unless existing_config && existing_config == config
|
66
|
+
redis.hset(:schedules, name, encode(config))
|
67
|
+
redis.sadd(:schedules_changed, name)
|
68
|
+
end
|
69
|
+
config
|
70
|
+
end
|
71
|
+
|
72
|
+
# retrive the schedule configuration for the given name
|
73
|
+
def get_schedule(name)
|
74
|
+
decode(redis.hget(:schedules, name))
|
75
|
+
end
|
76
|
+
|
77
|
+
# remove a given schedule by name
|
78
|
+
def remove_schedule(name)
|
79
|
+
redis.hdel(:schedules, name)
|
80
|
+
redis.sadd(:schedules_changed, name)
|
81
|
+
end
|
38
82
|
|
39
83
|
# This method is nearly identical to +enqueue+ only it also
|
40
84
|
# takes a timestamp which will be used to schedule the job
|
41
85
|
# for queueing. Until timestamp is in the past, the job will
|
42
86
|
# sit in the schedule list.
|
43
87
|
def enqueue_at(timestamp, klass, *args)
|
44
|
-
validate_job!(klass)
|
45
88
|
delayed_push(timestamp, job_to_hash(klass, args))
|
46
89
|
end
|
47
90
|
|
48
|
-
# Identical to +enqueue_at+, except you can also specify
|
49
|
-
# a queue in which the job will be placed after the
|
50
|
-
# timestamp has passed.
|
51
|
-
def enqueue_at_with_queue(queue, timestamp, klass, *args)
|
52
|
-
validate_job!(klass)
|
53
|
-
delayed_push(timestamp, job_to_hash_with_queue(queue, klass, args))
|
54
|
-
end
|
55
|
-
|
56
91
|
# Identical to enqueue_at but takes number_of_seconds_from_now
|
57
92
|
# instead of a timestamp.
|
58
93
|
def enqueue_in(number_of_seconds_from_now, klass, *args)
|
59
94
|
enqueue_at(Time.now + number_of_seconds_from_now, klass, *args)
|
60
95
|
end
|
61
96
|
|
62
|
-
# Identical to +enqueue_in+, except you can also specify
|
63
|
-
# a queue in which the job will be placed after the
|
64
|
-
# number of seconds has passed.
|
65
|
-
def enqueue_in_with_queue(queue, number_of_seconds_from_now, klass, *args)
|
66
|
-
enqueue_at_with_queue(queue, Time.now + number_of_seconds_from_now, klass, *args)
|
67
|
-
end
|
68
|
-
|
69
97
|
# Used internally to stuff the item into the schedule sorted list.
|
70
98
|
# +timestamp+ can be either in seconds or a datetime object
|
71
99
|
# Insertion if O(log(n)).
|
@@ -146,22 +174,18 @@ module ResqueScheduler
|
|
146
174
|
end
|
147
175
|
|
148
176
|
def count_all_scheduled_jobs
|
149
|
-
total_jobs = 0
|
177
|
+
total_jobs = 0
|
150
178
|
Array(redis.zrange(:delayed_queue_schedule, 0, -1)).each do |timestamp|
|
151
179
|
total_jobs += redis.llen("delayed:#{timestamp}").to_i
|
152
|
-
end
|
180
|
+
end
|
153
181
|
total_jobs
|
154
|
-
end
|
182
|
+
end
|
155
183
|
|
156
184
|
private
|
157
185
|
def job_to_hash(klass, args)
|
158
186
|
{:class => klass.to_s, :args => args, :queue => queue_from_class(klass)}
|
159
187
|
end
|
160
188
|
|
161
|
-
def job_to_hash_with_queue(queue, klass, args)
|
162
|
-
{:class => klass.to_s, :args => args, :queue => queue}
|
163
|
-
end
|
164
|
-
|
165
189
|
def clean_up_timestamp(key, timestamp)
|
166
190
|
# If the list is empty, remove it.
|
167
191
|
if 0 == redis.llen(key).to_i
|
@@ -170,16 +194,6 @@ module ResqueScheduler
|
|
170
194
|
end
|
171
195
|
end
|
172
196
|
|
173
|
-
def validate_job!(klass)
|
174
|
-
if klass.to_s.empty?
|
175
|
-
raise Resque::NoClassError.new("Jobs must be given a class.")
|
176
|
-
end
|
177
|
-
|
178
|
-
unless queue_from_class(klass)
|
179
|
-
raise Resque::NoQueueError.new("Jobs must be placed onto a queue.")
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
197
|
end
|
184
198
|
|
185
199
|
Resque.extend ResqueScheduler
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# Extend Resque::Server to add tabs
|
3
3
|
module ResqueScheduler
|
4
|
-
|
4
|
+
|
5
5
|
module Server
|
6
6
|
|
7
7
|
def self.included(base)
|
@@ -19,6 +19,7 @@ module ResqueScheduler
|
|
19
19
|
end
|
20
20
|
|
21
21
|
get "/schedule" do
|
22
|
+
Resque.reload_schedule! if Resque::Scheduler.dynamic
|
22
23
|
# Is there a better way to specify alternate template locations with sinatra?
|
23
24
|
erb File.read(File.join(File.dirname(__FILE__), 'server/views/scheduler.erb'))
|
24
25
|
end
|
@@ -26,9 +27,9 @@ module ResqueScheduler
|
|
26
27
|
post "/schedule/requeue" do
|
27
28
|
config = Resque.schedule[params['job_name']]
|
28
29
|
Resque::Scheduler.enqueue_from_config(config)
|
29
|
-
redirect
|
30
|
+
redirect url("/overview")
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
get "/delayed" do
|
33
34
|
# Is there a better way to specify alternate template locations with sinatra?
|
34
35
|
erb File.read(File.join(File.dirname(__FILE__), 'server/views/delayed.erb'))
|
@@ -38,11 +39,11 @@ module ResqueScheduler
|
|
38
39
|
# Is there a better way to specify alternate template locations with sinatra?
|
39
40
|
erb File.read(File.join(File.dirname(__FILE__), 'server/views/delayed_timestamp.erb'))
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
post "/delayed/queue_now" do
|
43
44
|
timestamp = params['timestamp']
|
44
45
|
Resque::Scheduler.enqueue_delayed_items_for_timestamp(timestamp.to_i) if timestamp.to_i > 0
|
45
|
-
redirect
|
46
|
+
redirect url("/overview")
|
46
47
|
end
|
47
48
|
|
48
49
|
end
|
@@ -53,5 +54,5 @@ module ResqueScheduler
|
|
53
54
|
Resque::Server.tabs << 'Delayed'
|
54
55
|
|
55
56
|
end
|
56
|
-
|
57
|
-
end
|
57
|
+
|
58
|
+
end
|
@@ -19,19 +19,19 @@
|
|
19
19
|
<% resque.delayed_queue_peek(start, start+20).each do |timestamp| %>
|
20
20
|
<tr>
|
21
21
|
<td>
|
22
|
-
<form action="<%=
|
22
|
+
<form action="<%= url "/delayed/queue_now" %>" method="post">
|
23
23
|
<input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
|
24
24
|
<input type="submit" value="Queue now">
|
25
25
|
</form>
|
26
26
|
</td>
|
27
|
-
<td><a href="<%=
|
27
|
+
<td><a href="<%= url "delayed/#{timestamp}" %>"><%= format_time(Time.at(timestamp)) %></a></td>
|
28
28
|
<td><%= delayed_timestamp_size = resque.delayed_timestamp_size(timestamp) %></td>
|
29
29
|
<% job = resque.delayed_timestamp_peek(timestamp, 0, 1).first %>
|
30
30
|
<td>
|
31
31
|
<% if job && delayed_timestamp_size == 1 %>
|
32
32
|
<%= h(job['class']) %>
|
33
33
|
<% else %>
|
34
|
-
<a href="<%=
|
34
|
+
<a href="<%= url "delayed/#{timestamp}" %>">see details</a>
|
35
35
|
<% end %>
|
36
36
|
</td>
|
37
37
|
<td><%= h(job['args'].inspect) if job && delayed_timestamp_size == 1 %></td>
|
@@ -15,11 +15,11 @@
|
|
15
15
|
<th>Queue</th>
|
16
16
|
<th>Arguments</th>
|
17
17
|
</tr>
|
18
|
-
<% Resque.schedule.keys.
|
18
|
+
<% Resque.schedule.keys.sort.each do |name| %>
|
19
19
|
<% config = Resque.schedule[name] %>
|
20
20
|
<tr>
|
21
21
|
<td>
|
22
|
-
<form action="<%=
|
22
|
+
<form action="<%= url "/schedule/requeue" %>" method="post">
|
23
23
|
<input type="hidden" name="job_name" value="<%= h name %>">
|
24
24
|
<input type="submit" value="Queue now">
|
25
25
|
</form>
|
@@ -27,8 +27,8 @@
|
|
27
27
|
<td><%= h name %></td>
|
28
28
|
<td><%= h config['description'] %></td>
|
29
29
|
<td style="white-space:nowrap"><%= (config['cron'].nil? && !config['every'].nil?) ?
|
30
|
-
h(
|
31
|
-
h(
|
30
|
+
h('every: ' + config['every']) :
|
31
|
+
h('cron: ' + config['cron']) %></td>
|
32
32
|
<td><%= (config['class'].nil? && !config['custom_job_class'].nil?) ?
|
33
33
|
h(config['custom_job_class']) :
|
34
34
|
h(config['class']) %></td>
|
data/resque-scheduler.gemspec
CHANGED
@@ -1,32 +1,29 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'resque_scheduler/version'
|
2
|
+
require File.expand_path("../lib/resque_scheduler/version", __FILE__)
|
5
3
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "resque-scheduler"
|
6
|
+
s.version = ResqueScheduler::Version
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ['Ben VandenBos']
|
9
|
+
s.email = ['bvandenbos@gmail.com']
|
10
|
+
s.homepage = "http://github.com/bvandenbos/resque-scheduler"
|
11
|
+
s.summary = "Light weight job scheduling on top of Resque"
|
12
|
+
s.description = %q{Light weight job scheduling on top of Resque.
|
14
13
|
Adds methods enqueue_at/enqueue_in to schedule jobs in the future.
|
15
14
|
Also supports queueing jobs on a fixed, cron-like schedule.}
|
15
|
+
|
16
|
+
s.required_rubygems_version = ">= 1.3.6"
|
17
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
spec.add_development_dependency 'rubocop' unless RUBY_VERSION < '1.9'
|
28
|
-
|
29
|
-
spec.add_runtime_dependency 'redis', '>= 2.0.1'
|
30
|
-
spec.add_runtime_dependency 'resque', ['>= 1.8.0', '< 1.25.0']
|
31
|
-
spec.add_runtime_dependency 'rufus-scheduler', '>= 0'
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
21
|
+
s.require_path = 'lib'
|
22
|
+
|
23
|
+
s.add_runtime_dependency(%q<redis>, [">= 2.0.1"])
|
24
|
+
s.add_runtime_dependency(%q<resque>, [">= 1.8.0"])
|
25
|
+
s.add_runtime_dependency(%q<rufus-scheduler>, [">= 0"])
|
26
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
27
|
+
s.add_development_dependency(%q<rack-test>, [">= 0"])
|
28
|
+
|
32
29
|
end
|
data/test/delayed_queue_test.rb
CHANGED
@@ -28,34 +28,7 @@ class Resque::DelayedQueueTest < Test::Unit::TestCase
|
|
28
28
|
# Confirm the item came out correctly
|
29
29
|
assert_equal('SomeIvarJob', item['class'], "Should be the same class that we queued")
|
30
30
|
assert_equal(["path"], item['args'], "Should have the same arguments that we queued")
|
31
|
-
|
32
|
-
# And now confirm the keys are gone
|
33
|
-
assert(!Resque.redis.exists("delayed:#{timestamp.to_i}"))
|
34
|
-
assert_equal(0, Resque.redis.zcard(:delayed_queue_schedule), "delayed queue should be empty")
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_enqueue_at_with_queue_inserts_into_correct_queue
|
38
|
-
timestamp = Time.now - 1 # 1 second ago (in the past, should come out right away)
|
39
|
-
|
40
|
-
assert_equal(0, Resque.redis.llen("delayed:#{timestamp.to_i}").to_i, "delayed queue should be empty to start")
|
41
|
-
|
42
|
-
Resque.enqueue_at_with_queue("critical", timestamp, SomeIvarJob, "path")
|
43
|
-
|
44
|
-
# Confirm the correct keys were added
|
45
|
-
assert_equal(1, Resque.redis.llen("delayed:#{timestamp.to_i}").to_i, "delayed queue should have one entry now")
|
46
|
-
assert_equal(1, Resque.redis.zcard(:delayed_queue_schedule), "The delayed_queue_schedule should have 1 entry now")
|
47
|
-
|
48
|
-
read_timestamp = Resque.next_delayed_timestamp
|
49
|
-
|
50
|
-
# Confirm the timestamp came out correctly
|
51
|
-
assert_equal(timestamp.to_i, read_timestamp, "The timestamp we pull out of redis should match the one we put in")
|
52
|
-
item = Resque.next_item_for_timestamp(read_timestamp)
|
53
|
-
|
54
|
-
# Confirm the item came out correctly
|
55
|
-
assert_equal('SomeIvarJob', item['class'], "Should be the same class that we queued")
|
56
|
-
assert_equal(["path"], item['args'], "Should have the same arguments that we queued")
|
57
|
-
assert_equal('critical', item['queue'], "Should have the queue that we asked for")
|
58
|
-
|
31
|
+
|
59
32
|
# And now confirm the keys are gone
|
60
33
|
assert(!Resque.redis.exists("delayed:#{timestamp.to_i}"))
|
61
34
|
assert_equal(0, Resque.redis.zcard(:delayed_queue_schedule), "delayed queue should be empty")
|
@@ -168,10 +141,10 @@ class Resque::DelayedQueueTest < Test::Unit::TestCase
|
|
168
141
|
Resque.expects(:queue_from_class).never # Should NOT need to load the class
|
169
142
|
Resque::Scheduler.handle_delayed_items(t)
|
170
143
|
end
|
171
|
-
|
144
|
+
|
172
145
|
def test_enqueue_delayed_items_for_timestamp
|
173
146
|
t = Time.now + 60
|
174
|
-
|
147
|
+
|
175
148
|
Resque.enqueue_at(t, SomeIvarJob)
|
176
149
|
Resque.enqueue_at(t, SomeIvarJob)
|
177
150
|
|
@@ -180,7 +153,7 @@ class Resque::DelayedQueueTest < Test::Unit::TestCase
|
|
180
153
|
Resque.expects(:queue_from_class).never # Should NOT need to load the class
|
181
154
|
|
182
155
|
Resque::Scheduler.enqueue_delayed_items_for_timestamp(t)
|
183
|
-
|
156
|
+
|
184
157
|
# delayed queue for timestamp should be empty
|
185
158
|
assert_equal(0, Resque.delayed_timestamp_peek(t, 0, 3).length)
|
186
159
|
end
|
@@ -233,7 +206,7 @@ class Resque::DelayedQueueTest < Test::Unit::TestCase
|
|
233
206
|
assert_equal(2, Resque.remove_delayed(SomeIvarJob, "bar"))
|
234
207
|
assert_equal(1, Resque.delayed_queue_schedule_size)
|
235
208
|
end
|
236
|
-
|
209
|
+
|
237
210
|
def test_remove_specific_item_in_group_of_other_items_at_different_timestamps
|
238
211
|
t = Time.now + 120
|
239
212
|
Resque.enqueue_at(t, SomeIvarJob, "foo")
|
@@ -244,13 +217,4 @@ class Resque::DelayedQueueTest < Test::Unit::TestCase
|
|
244
217
|
assert_equal(2, Resque.remove_delayed(SomeIvarJob, "bar"))
|
245
218
|
assert_equal(2, Resque.count_all_scheduled_jobs)
|
246
219
|
end
|
247
|
-
|
248
|
-
def test_invalid_job_class
|
249
|
-
assert_raise Resque::NoClassError do
|
250
|
-
Resque.enqueue_in(10, nil)
|
251
|
-
end
|
252
|
-
assert_raise Resque::NoQueueError do
|
253
|
-
Resque.enqueue_in(10, String) # string serves as invalid Job class
|
254
|
-
end
|
255
|
-
end
|
256
220
|
end
|
data/test/redis-test.conf
CHANGED
@@ -112,4 +112,4 @@ databases 16
|
|
112
112
|
# Glue small output buffers together in order to send small replies in a
|
113
113
|
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
114
114
|
# in terms of number of queries per second. Use 'yes' if unsure.
|
115
|
-
|
115
|
+
glueoutputbuf yes
|
data/test/resque-web_test.rb
CHANGED
@@ -10,10 +10,9 @@ context "on GET to /schedule" do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
context "on GET to /schedule with scheduled jobs" do
|
13
|
-
setup do
|
13
|
+
setup do
|
14
14
|
ENV['rails_env'] = 'production'
|
15
|
-
Resque.schedule = {:some_ivar_job => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp", 'rails_env' => 'production'}
|
16
|
-
:some_other_job => {'queue' => 'high', 'class' => 'SomeOtherJob', 'args' => {:b => 'blah'}}}
|
15
|
+
Resque.schedule = {:some_ivar_job => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp", 'rails_env' => 'production'}}
|
17
16
|
Resque::Scheduler.load_schedule!
|
18
17
|
get "/schedule"
|
19
18
|
end
|
data/test/scheduler_args_test.rb
CHANGED
@@ -14,7 +14,7 @@ context "scheduling jobs with arguments" do
|
|
14
14
|
test "calls the worker without arguments when 'args' is blank in the config" do
|
15
15
|
Resque::Scheduler.enqueue_from_config(YAML.load(<<-YAML))
|
16
16
|
class: SomeIvarJob
|
17
|
-
args:
|
17
|
+
args:
|
18
18
|
YAML
|
19
19
|
SomeIvarJob.expects(:perform).once.with()
|
20
20
|
Resque.reserve('ivar').perform
|
data/test/scheduler_test.rb
CHANGED
@@ -7,7 +7,12 @@ class Resque::SchedulerTest < Test::Unit::TestCase
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def setup
|
10
|
+
Resque::Scheduler.dynamic = false
|
11
|
+
Resque.redis.del(:schedules)
|
12
|
+
Resque.redis.del(:schedules_changed)
|
13
|
+
Resque::Scheduler.mute = true
|
10
14
|
Resque::Scheduler.clear_schedule!
|
15
|
+
Resque::Scheduler.send(:class_variable_set, :@@scheduled_jobs, {})
|
11
16
|
end
|
12
17
|
|
13
18
|
def test_enqueue_from_config_puts_stuff_in_the_resque_queue_without_class_loaded
|
@@ -20,16 +25,11 @@ class Resque::SchedulerTest < Test::Unit::TestCase
|
|
20
25
|
Resque::Scheduler.enqueue_from_config('every' => '1m', 'class' => 'JamesJob', 'args' => '/tmp', 'queue' => 'james_queue')
|
21
26
|
end
|
22
27
|
|
23
|
-
def test_enqueue_from_config_doesnt_crash_on_exception_when_enqueueing
|
24
|
-
Resque::Job.stubs(:create).raises(Resque::NoQueueError, 'test exception').with(:ivar, 'SomeIvarJob', '/tmp')
|
25
|
-
Resque::Scheduler.enqueue_from_config('cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp")
|
26
|
-
end
|
27
|
-
|
28
28
|
def test_enqueue_from_config_puts_stuff_in_the_resque_queue
|
29
29
|
Resque::Job.stubs(:create).once.returns(true).with(:ivar, 'SomeIvarJob', '/tmp')
|
30
30
|
Resque::Scheduler.enqueue_from_config('cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp")
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def test_enqueue_from_config_with_custom_class_job_in_the_resque_queue
|
34
34
|
FakeJob.stubs(:scheduled).once.returns(true).with(:ivar, 'SomeIvarJob', '/tmp')
|
35
35
|
Resque::Scheduler.enqueue_from_config('cron' => "* * * * *", 'class' => 'SomeIvarJob', 'custom_job_class' => 'Resque::SchedulerTest::FakeJob', 'args' => "/tmp")
|
@@ -80,11 +80,164 @@ class Resque::SchedulerTest < Test::Unit::TestCase
|
|
80
80
|
Resque::Scheduler.load_schedule!
|
81
81
|
|
82
82
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
83
|
+
assert Resque::Scheduler.scheduled_jobs.include?(:some_ivar_job)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_can_reload_schedule
|
87
|
+
Resque::Scheduler.dynamic = true
|
88
|
+
Resque.schedule = {"some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}}
|
89
|
+
|
90
|
+
Resque::Scheduler.load_schedule!
|
91
|
+
|
92
|
+
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
93
|
+
assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job")
|
94
|
+
|
95
|
+
Resque.redis.del(:schedules)
|
96
|
+
Resque.redis.hset(:schedules, "some_ivar_job2", Resque.encode(
|
97
|
+
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}
|
98
|
+
))
|
99
|
+
|
100
|
+
Resque::Scheduler.reload_schedule!
|
101
|
+
|
102
|
+
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
103
|
+
|
104
|
+
assert_equal '/tmp/2', Resque.schedule["some_ivar_job2"]["args"]
|
105
|
+
assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job2")
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_load_schedule_job
|
109
|
+
Resque::Scheduler.load_schedule_job("some_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"})
|
110
|
+
|
111
|
+
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
112
|
+
assert_equal(1, Resque::Scheduler.scheduled_jobs.size)
|
113
|
+
assert Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_load_schedule_job_with_no_cron
|
117
|
+
Resque::Scheduler.load_schedule_job("some_ivar_job", {'class' => 'SomeIvarJob', 'args' => "/tmp"})
|
118
|
+
|
119
|
+
assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
120
|
+
assert_equal(0, Resque::Scheduler.scheduled_jobs.size)
|
121
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_load_schedule_job_with_blank_cron
|
125
|
+
Resque::Scheduler.load_schedule_job("some_ivar_job", {'cron' => '', 'class' => 'SomeIvarJob', 'args' => "/tmp"})
|
126
|
+
|
127
|
+
assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
128
|
+
assert_equal(0, Resque::Scheduler.scheduled_jobs.size)
|
129
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?("some_ivar_job")
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_update_schedule
|
133
|
+
Resque::Scheduler.dynamic = true
|
134
|
+
Resque.schedule = {
|
135
|
+
"some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"},
|
136
|
+
"another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"},
|
137
|
+
"stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
|
138
|
+
}
|
139
|
+
|
140
|
+
Resque::Scheduler.load_schedule!
|
141
|
+
|
142
|
+
Resque.set_schedule("some_ivar_job",
|
143
|
+
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}
|
144
|
+
)
|
145
|
+
Resque.set_schedule("new_ivar_job",
|
146
|
+
{'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"}
|
147
|
+
)
|
148
|
+
Resque.set_schedule("stay_put_job",
|
149
|
+
{'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
|
150
|
+
)
|
151
|
+
Resque.remove_schedule("another_ivar_job")
|
152
|
+
|
153
|
+
Resque::Scheduler.update_schedule
|
154
|
+
|
155
|
+
assert_equal(3, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
156
|
+
assert_equal(3, Resque::Scheduler.scheduled_jobs.size)
|
157
|
+
%w(some_ivar_job new_ivar_job stay_put_job).each do |job_name|
|
158
|
+
assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
|
159
|
+
assert Resque.schedule.keys.include?(job_name)
|
160
|
+
end
|
161
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job")
|
162
|
+
assert !Resque.schedule.keys.include?("another_ivar_job")
|
163
|
+
assert_equal 0, Resque.redis.scard(:schedules_changed)
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_update_schedule_with_mocks
|
167
|
+
Resque::Scheduler.dynamic = true
|
168
|
+
Resque.schedule = {
|
169
|
+
"some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"},
|
170
|
+
"another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"},
|
171
|
+
"stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
|
172
|
+
}
|
173
|
+
|
174
|
+
Resque::Scheduler.load_schedule!
|
175
|
+
|
176
|
+
Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["some_ivar_job"].job_id)
|
177
|
+
Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["another_ivar_job"].job_id)
|
178
|
+
|
179
|
+
Resque.set_schedule("some_ivar_job",
|
180
|
+
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}
|
181
|
+
)
|
182
|
+
Resque.set_schedule("new_ivar_job",
|
183
|
+
{'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"}
|
184
|
+
)
|
185
|
+
Resque.set_schedule("stay_put_job",
|
186
|
+
{'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"}
|
187
|
+
)
|
188
|
+
Resque.remove_schedule("another_ivar_job")
|
189
|
+
|
190
|
+
Resque::Scheduler.update_schedule
|
191
|
+
|
192
|
+
assert_equal(3, Resque::Scheduler.scheduled_jobs.size)
|
193
|
+
%w(some_ivar_job new_ivar_job stay_put_job).each do |job_name|
|
194
|
+
assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
|
195
|
+
assert Resque.schedule.keys.include?(job_name)
|
196
|
+
end
|
197
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job")
|
198
|
+
assert !Resque.schedule.keys.include?("another_ivar_job")
|
199
|
+
assert_equal 0, Resque.redis.scard(:schedules_changed)
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_set_schedules
|
203
|
+
Resque::Scheduler.dynamic = true
|
204
|
+
Resque.schedule = {"my_ivar_job" => {
|
205
|
+
'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75"
|
206
|
+
}}
|
207
|
+
assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75"},
|
208
|
+
Resque.decode(Resque.redis.hget(:schedules, "my_ivar_job")))
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_set_schedule
|
212
|
+
Resque.set_schedule("some_ivar_job", {
|
213
|
+
'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/22"
|
214
|
+
})
|
215
|
+
assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/22"},
|
216
|
+
Resque.decode(Resque.redis.hget(:schedules, "some_ivar_job")))
|
217
|
+
assert Resque.redis.sismember(:schedules_changed, "some_ivar_job")
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_get_schedule
|
221
|
+
Resque.redis.hset(:schedules, "some_ivar_job2", Resque.encode(
|
222
|
+
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/33"}
|
223
|
+
))
|
224
|
+
assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/33"},
|
225
|
+
Resque.get_schedule("some_ivar_job2"))
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_remove_schedule
|
229
|
+
Resque.redis.hset(:schedules, "some_ivar_job3", Resque.encode(
|
230
|
+
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/44"}
|
231
|
+
))
|
232
|
+
Resque.remove_schedule("some_ivar_job3")
|
233
|
+
assert_equal nil, Resque.redis.hget(:schedules, "some_ivar_job3")
|
234
|
+
assert Resque.redis.sismember(:schedules_changed, "some_ivar_job3")
|
83
235
|
end
|
84
236
|
|
85
237
|
def test_adheres_to_lint
|
86
238
|
assert_nothing_raised do
|
87
239
|
Resque::Plugin.lint(Resque::Scheduler)
|
240
|
+
Resque::Plugin.lint(ResqueScheduler)
|
88
241
|
end
|
89
242
|
end
|
90
243
|
|