resque-scheduler 2.5.5 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +12 -6
- data/.rubocop.yml +18 -113
- data/.rubocop_todo.yml +29 -0
- data/.simplecov +3 -1
- data/.travis.yml +12 -4
- data/.vagrant-provision-as-vagrant.sh +15 -0
- data/.vagrant-provision.sh +23 -0
- data/.vagrant-skel/bash_profile +7 -0
- data/.vagrant-skel/bashrc +7 -0
- data/AUTHORS.md +5 -0
- data/Gemfile +1 -2
- data/HISTORY.md +18 -0
- data/README.md +39 -11
- data/ROADMAP.md +0 -6
- data/Rakefile +11 -19
- data/Vagrantfile +14 -0
- data/bin/resque-scheduler +2 -2
- data/examples/Rakefile +1 -1
- data/examples/config/initializers/resque-web.rb +2 -2
- data/examples/dynamic-scheduling/app/jobs/fix_schedules_job.rb +2 -4
- data/examples/dynamic-scheduling/app/jobs/send_email_job.rb +1 -1
- data/examples/dynamic-scheduling/app/models/user.rb +2 -2
- data/examples/dynamic-scheduling/lib/tasks/resque.rake +2 -2
- data/lib/resque-scheduler.rb +3 -1
- data/lib/resque/scheduler.rb +112 -168
- data/lib/resque/scheduler/cli.rb +144 -0
- data/lib/resque/scheduler/configuration.rb +73 -0
- data/lib/resque/scheduler/delaying_extensions.rb +278 -0
- data/lib/resque/scheduler/env.rb +61 -0
- data/lib/resque/scheduler/extension.rb +13 -0
- data/lib/resque/scheduler/lock.rb +2 -1
- data/lib/resque/scheduler/lock/base.rb +6 -2
- data/lib/resque/scheduler/lock/basic.rb +4 -5
- data/lib/resque/scheduler/lock/resilient.rb +30 -37
- data/lib/resque/scheduler/locking.rb +94 -0
- data/lib/resque/scheduler/logger_builder.rb +72 -0
- data/lib/resque/scheduler/plugin.rb +31 -0
- data/lib/resque/scheduler/scheduling_extensions.rb +150 -0
- data/lib/resque/scheduler/server.rb +246 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed.erb +2 -1
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed_schedules.erb +0 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed_timestamp.erb +0 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/requeue-params.erb +0 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/scheduler.erb +16 -1
- data/lib/{resque_scheduler → resque/scheduler}/server/views/search.erb +2 -1
- data/lib/{resque_scheduler → resque/scheduler}/server/views/search_form.erb +0 -0
- data/lib/resque/scheduler/signal_handling.rb +40 -0
- data/lib/{resque_scheduler → resque/scheduler}/tasks.rb +3 -5
- data/lib/resque/scheduler/util.rb +41 -0
- data/lib/resque/scheduler/version.rb +7 -0
- data/resque-scheduler.gemspec +21 -19
- data/script/migrate_to_timestamps_set.rb +5 -3
- data/tasks/resque_scheduler.rake +1 -1
- data/test/cli_test.rb +26 -69
- data/test/delayed_queue_test.rb +262 -169
- data/test/env_test.rb +41 -0
- data/test/resque-web_test.rb +169 -48
- data/test/scheduler_args_test.rb +73 -41
- data/test/scheduler_hooks_test.rb +9 -8
- data/test/scheduler_locking_test.rb +55 -36
- data/test/scheduler_setup_test.rb +52 -15
- data/test/scheduler_task_test.rb +15 -10
- data/test/scheduler_test.rb +215 -114
- data/test/support/redis_instance.rb +32 -33
- data/test/test_helper.rb +33 -36
- data/test/util_test.rb +11 -0
- metadata +113 -57
- data/lib/resque/scheduler_locking.rb +0 -91
- data/lib/resque_scheduler.rb +0 -386
- data/lib/resque_scheduler/cli.rb +0 -160
- data/lib/resque_scheduler/logger_builder.rb +0 -72
- data/lib/resque_scheduler/plugin.rb +0 -28
- data/lib/resque_scheduler/server.rb +0 -183
- data/lib/resque_scheduler/util.rb +0 -34
- data/lib/resque_scheduler/version.rb +0 -5
- data/test/redis-test.conf +0 -108
@@ -1,23 +1,24 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
|
-
context
|
4
|
-
setup
|
5
|
-
Resque.redis.flushall
|
6
|
-
end
|
4
|
+
context 'scheduling jobs with hooks' do
|
5
|
+
setup { Resque.redis.flushall }
|
7
6
|
|
8
|
-
test
|
7
|
+
test 'before_schedule hook that does not return false should be enqueued' do
|
9
8
|
enqueue_time = Time.now
|
10
9
|
SomeRealClass.expects(:before_schedule_example).with(:foo)
|
11
10
|
SomeRealClass.expects(:after_schedule_example).with(:foo)
|
12
11
|
Resque.enqueue_at(enqueue_time.to_i, SomeRealClass, :foo)
|
13
|
-
assert_equal(1, Resque.delayed_timestamp_size(enqueue_time.to_i),
|
12
|
+
assert_equal(1, Resque.delayed_timestamp_size(enqueue_time.to_i),
|
13
|
+
'job should be enqueued')
|
14
14
|
end
|
15
15
|
|
16
|
-
test
|
16
|
+
test 'before_schedule hook that returns false should not be enqueued' do
|
17
17
|
enqueue_time = Time.now
|
18
18
|
SomeRealClass.expects(:before_schedule_example).with(:foo).returns(false)
|
19
19
|
SomeRealClass.expects(:after_schedule_example).never
|
20
20
|
Resque.enqueue_at(enqueue_time.to_i, SomeRealClass, :foo)
|
21
|
-
assert_equal(0, Resque.delayed_timestamp_size(enqueue_time.to_i),
|
21
|
+
assert_equal(0, Resque.delayed_timestamp_size(enqueue_time.to_i),
|
22
|
+
'job should not be enqueued')
|
22
23
|
end
|
23
24
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
module LockTestHelper
|
@@ -8,36 +9,41 @@ end
|
|
8
9
|
|
9
10
|
context '#master_lock_key' do
|
10
11
|
setup do
|
11
|
-
@subject = Class.new { extend Resque::
|
12
|
+
@subject = Class.new { extend Resque::Scheduler::Locking }
|
12
13
|
end
|
13
14
|
|
14
15
|
teardown do
|
15
16
|
Resque.redis.del(@subject.master_lock.key)
|
16
17
|
end
|
17
18
|
|
18
|
-
test '
|
19
|
-
assert_equal
|
19
|
+
test 'should have resque prefix' do
|
20
|
+
assert_equal(
|
21
|
+
@subject.master_lock.key, 'resque:resque_scheduler_master_lock'
|
22
|
+
)
|
20
23
|
end
|
21
24
|
|
22
25
|
context 'with a prefix set via ENV' do
|
23
26
|
setup do
|
24
27
|
ENV['RESQUE_SCHEDULER_MASTER_LOCK_PREFIX'] = 'my.prefix'
|
25
|
-
@subject = Class.new { extend Resque::
|
28
|
+
@subject = Class.new { extend Resque::Scheduler::Locking }
|
26
29
|
end
|
27
30
|
|
28
31
|
teardown do
|
29
32
|
Resque.redis.del(@subject.master_lock.key)
|
30
33
|
end
|
31
34
|
|
32
|
-
test '
|
33
|
-
assert_equal
|
35
|
+
test 'should have ENV prefix' do
|
36
|
+
assert_equal(
|
37
|
+
@subject.master_lock.key,
|
38
|
+
'resque:my.prefix:resque_scheduler_master_lock'
|
39
|
+
)
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
43
|
context 'with a namespace set for resque' do
|
38
44
|
setup do
|
39
45
|
Resque.redis.namespace = 'my.namespace'
|
40
|
-
@subject = Class.new { extend Resque::
|
46
|
+
@subject = Class.new { extend Resque::Scheduler::Locking }
|
41
47
|
end
|
42
48
|
|
43
49
|
teardown do
|
@@ -45,15 +51,17 @@ context '#master_lock_key' do
|
|
45
51
|
Resque.redis.del(@subject.master_lock.key)
|
46
52
|
end
|
47
53
|
|
48
|
-
test '
|
49
|
-
assert_equal
|
54
|
+
test 'should have resque prefix' do
|
55
|
+
assert_equal(
|
56
|
+
@subject.master_lock.key, 'my.namespace:resque_scheduler_master_lock'
|
57
|
+
)
|
50
58
|
end
|
51
59
|
|
52
60
|
context 'with a prefix set via ENV' do
|
53
61
|
setup do
|
54
62
|
Resque.redis.namespace = 'my.namespace'
|
55
63
|
ENV['RESQUE_SCHEDULER_MASTER_LOCK_PREFIX'] = 'my.prefix'
|
56
|
-
@subject = Class.new { extend Resque::
|
64
|
+
@subject = Class.new { extend Resque::Scheduler::Locking }
|
57
65
|
end
|
58
66
|
|
59
67
|
teardown do
|
@@ -61,45 +69,50 @@ context '#master_lock_key' do
|
|
61
69
|
Resque.redis.del(@subject.master_lock.key)
|
62
70
|
end
|
63
71
|
|
64
|
-
test '
|
65
|
-
assert_equal
|
72
|
+
test 'should have ENV prefix' do
|
73
|
+
assert_equal(
|
74
|
+
@subject.master_lock.key,
|
75
|
+
'my.namespace:my.prefix:resque_scheduler_master_lock'
|
76
|
+
)
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
71
|
-
context 'Resque::
|
82
|
+
context 'Resque::Scheduler::Locking' do
|
72
83
|
setup do
|
73
|
-
@subject = Class.new { extend Resque::
|
84
|
+
@subject = Class.new { extend Resque::Scheduler::Locking }
|
74
85
|
end
|
75
86
|
|
76
87
|
teardown do
|
77
88
|
Resque.redis.del(@subject.master_lock.key)
|
78
89
|
end
|
79
90
|
|
80
|
-
test '
|
91
|
+
test 'should use the basic lock mechanism for <= Redis 2.4' do
|
81
92
|
Resque.redis.stubs(:info).returns('redis_version' => '2.4.16')
|
82
93
|
|
83
94
|
assert_equal @subject.master_lock.class, Resque::Scheduler::Lock::Basic
|
84
95
|
end
|
85
96
|
|
86
|
-
test '
|
97
|
+
test 'should use the resilient lock mechanism for > Redis 2.4' do
|
87
98
|
Resque.redis.stubs(:info).returns('redis_version' => '2.5.12')
|
88
99
|
|
89
|
-
assert_equal
|
100
|
+
assert_equal(
|
101
|
+
@subject.master_lock.class, Resque::Scheduler::Lock::Resilient
|
102
|
+
)
|
90
103
|
end
|
91
104
|
|
92
|
-
test '
|
105
|
+
test 'should be the master if the lock is held' do
|
93
106
|
@subject.master_lock.acquire!
|
94
|
-
assert @subject.
|
107
|
+
assert @subject.master?, 'should be master'
|
95
108
|
end
|
96
109
|
|
97
|
-
test '
|
110
|
+
test 'should not be the master if the lock is held by someone else' do
|
98
111
|
Resque.redis.set(@subject.master_lock.key, 'somethingelse:1234')
|
99
|
-
assert !@subject.
|
112
|
+
assert !@subject.master?, 'should not be master'
|
100
113
|
end
|
101
114
|
|
102
|
-
test
|
115
|
+
test 'release_master_lock should delegate to master_lock' do
|
103
116
|
@subject.master_lock.expects(:release!)
|
104
117
|
@subject.release_master_lock!
|
105
118
|
end
|
@@ -111,13 +124,13 @@ context 'Resque::Scheduler::Lock::Base' do
|
|
111
124
|
end
|
112
125
|
|
113
126
|
test '#acquire! should be not implemented' do
|
114
|
-
|
127
|
+
assert_raises NotImplementedError do
|
115
128
|
@lock.acquire!
|
116
129
|
end
|
117
130
|
end
|
118
131
|
|
119
132
|
test '#locked? should be not implemented' do
|
120
|
-
|
133
|
+
assert_raises NotImplementedError do
|
121
134
|
@lock.locked?
|
122
135
|
end
|
123
136
|
end
|
@@ -140,16 +153,17 @@ context 'Resque::Scheduler::Lock::Basic' do
|
|
140
153
|
assert !@lock.locked?
|
141
154
|
end
|
142
155
|
|
143
|
-
test 'you should not be able to acquire the lock if someone
|
156
|
+
test 'you should not be able to acquire the lock if someone ' \
|
157
|
+
'else holds it' do
|
144
158
|
lock_is_not_held(@lock)
|
145
159
|
|
146
160
|
assert !@lock.acquire!
|
147
161
|
end
|
148
162
|
|
149
|
-
test
|
163
|
+
test 'the lock should receive a TTL on acquiring' do
|
150
164
|
@lock.acquire!
|
151
165
|
|
152
|
-
assert Resque.redis.ttl(@lock.key) > 0,
|
166
|
+
assert Resque.redis.ttl(@lock.key) > 0, 'lock should expire'
|
153
167
|
end
|
154
168
|
|
155
169
|
test 'releasing should release the master lock' do
|
@@ -167,7 +181,7 @@ context 'Resque::Scheduler::Lock::Basic' do
|
|
167
181
|
|
168
182
|
@lock.locked?
|
169
183
|
|
170
|
-
assert Resque.redis.ttl(@lock.key) > 10,
|
184
|
+
assert Resque.redis.ttl(@lock.key) > 10, 'TTL should have been updated'
|
171
185
|
end
|
172
186
|
|
173
187
|
test 'checking the lock should not increase the TTL if we do not hold it' do
|
@@ -176,7 +190,8 @@ context 'Resque::Scheduler::Lock::Basic' do
|
|
176
190
|
|
177
191
|
@lock.locked?
|
178
192
|
|
179
|
-
assert Resque.redis.ttl(@lock.key) <= 10,
|
193
|
+
assert Resque.redis.ttl(@lock.key) <= 10,
|
194
|
+
'TTL should not have been updated'
|
180
195
|
end
|
181
196
|
end
|
182
197
|
|
@@ -184,7 +199,8 @@ context 'Resque::Scheduler::Lock::Resilient' do
|
|
184
199
|
include LockTestHelper
|
185
200
|
|
186
201
|
if !Resque::Scheduler.supports_lua?
|
187
|
-
puts
|
202
|
+
puts '*** Skipping Resque::Scheduler::Lock::Resilient ' \
|
203
|
+
'tests, as they require Redis >= 2.5.'
|
188
204
|
else
|
189
205
|
setup do
|
190
206
|
@lock = Resque::Scheduler::Lock::Resilient.new('test_resilient_lock')
|
@@ -200,16 +216,17 @@ context 'Resque::Scheduler::Lock::Resilient' do
|
|
200
216
|
assert !@lock.locked?, 'you should not have the lock'
|
201
217
|
end
|
202
218
|
|
203
|
-
test 'you should not be able to acquire the lock if someone
|
219
|
+
test 'you should not be able to acquire the lock if someone ' \
|
220
|
+
'else holds it' do
|
204
221
|
lock_is_not_held(@lock)
|
205
222
|
|
206
223
|
assert !@lock.acquire!
|
207
224
|
end
|
208
225
|
|
209
|
-
test
|
226
|
+
test 'the lock should receive a TTL on acquiring' do
|
210
227
|
@lock.acquire!
|
211
228
|
|
212
|
-
assert Resque.redis.ttl(@lock.key) > 0,
|
229
|
+
assert Resque.redis.ttl(@lock.key) > 0, 'lock should expire'
|
213
230
|
end
|
214
231
|
|
215
232
|
test 'releasing should release the master lock' do
|
@@ -227,16 +244,18 @@ context 'Resque::Scheduler::Lock::Resilient' do
|
|
227
244
|
|
228
245
|
@lock.locked?
|
229
246
|
|
230
|
-
assert Resque.redis.ttl(@lock.key) > 10,
|
247
|
+
assert Resque.redis.ttl(@lock.key) > 10, 'TTL should have been updated'
|
231
248
|
end
|
232
249
|
|
233
|
-
test 'checking the lock should not increase the TTL if we do
|
250
|
+
test 'checking the lock should not increase the TTL if we do ' \
|
251
|
+
'not hold it' do
|
234
252
|
Resque.redis.setex(@lock.key, 10, @lock.value)
|
235
253
|
lock_is_not_held(@lock)
|
236
254
|
|
237
255
|
@lock.locked?
|
238
256
|
|
239
|
-
assert Resque.redis.ttl(@lock.key) <= 10,
|
257
|
+
assert Resque.redis.ttl(@lock.key) <= 10,
|
258
|
+
'TTL should not have been updated'
|
240
259
|
end
|
241
260
|
|
242
261
|
test 'setting the lock timeout changes the key TTL if we hold it' do
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
|
-
context
|
4
|
+
context 'Resque::Scheduler' do
|
4
5
|
setup do
|
5
6
|
ENV['VERBOSE'] = nil
|
6
7
|
nullify_logger
|
@@ -13,16 +14,16 @@ context "Resque::Scheduler" do
|
|
13
14
|
|
14
15
|
test 'set custom logger' do
|
15
16
|
custom_logger = MonoLogger.new('/dev/null')
|
16
|
-
Resque::Scheduler.logger
|
17
|
-
assert_equal(custom_logger, Resque::Scheduler.logger)
|
17
|
+
Resque::Scheduler.send(:logger=, custom_logger)
|
18
|
+
assert_equal(custom_logger, Resque::Scheduler.send(:logger))
|
18
19
|
end
|
19
20
|
|
20
21
|
test 'configure block' do
|
21
|
-
Resque::Scheduler.
|
22
|
+
Resque::Scheduler.quiet = false
|
22
23
|
Resque::Scheduler.configure do |c|
|
23
|
-
c.
|
24
|
+
c.quiet = true
|
24
25
|
end
|
25
|
-
assert_equal(Resque::Scheduler.
|
26
|
+
assert_equal(Resque::Scheduler.quiet, true)
|
26
27
|
end
|
27
28
|
|
28
29
|
context 'when getting the env' do
|
@@ -57,16 +58,17 @@ context "Resque::Scheduler" do
|
|
57
58
|
|
58
59
|
test 'uses STDOUT' do
|
59
60
|
assert_equal(
|
60
|
-
Resque::Scheduler.logger
|
61
|
+
Resque::Scheduler.send(:logger)
|
62
|
+
.instance_variable_get(:@logdev).dev, $stdout
|
61
63
|
)
|
62
64
|
end
|
63
65
|
|
64
66
|
test 'not verbose' do
|
65
|
-
assert Resque::Scheduler.logger.level > MonoLogger::DEBUG
|
67
|
+
assert Resque::Scheduler.send(:logger).level > MonoLogger::DEBUG
|
66
68
|
end
|
67
69
|
|
68
|
-
test 'not
|
69
|
-
assert Resque::Scheduler.logger.level < MonoLogger::FATAL
|
70
|
+
test 'not quieted' do
|
71
|
+
assert Resque::Scheduler.send(:logger).level < MonoLogger::FATAL
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -77,19 +79,54 @@ context "Resque::Scheduler" do
|
|
77
79
|
test 'uses logfile' do
|
78
80
|
Resque::Scheduler.logfile = '/dev/null'
|
79
81
|
assert_equal(
|
80
|
-
Resque::Scheduler.logger
|
82
|
+
Resque::Scheduler.send(:logger)
|
83
|
+
.instance_variable_get(:@logdev).filename,
|
81
84
|
'/dev/null'
|
82
85
|
)
|
83
86
|
end
|
84
87
|
|
85
88
|
test 'set verbosity' do
|
86
89
|
Resque::Scheduler.verbose = true
|
87
|
-
assert Resque::Scheduler.logger.level == MonoLogger::DEBUG
|
90
|
+
assert Resque::Scheduler.send(:logger).level == MonoLogger::DEBUG
|
88
91
|
end
|
89
92
|
|
90
|
-
test '
|
91
|
-
Resque::Scheduler.
|
92
|
-
assert Resque::Scheduler.logger.level == MonoLogger::FATAL
|
93
|
+
test 'quiet logger' do
|
94
|
+
Resque::Scheduler.quiet = true
|
95
|
+
assert Resque::Scheduler.send(:logger).level == MonoLogger::FATAL
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'logger with json formatter' do
|
100
|
+
setup do
|
101
|
+
nullify_logger
|
102
|
+
Resque::Scheduler.logformat = 'json'
|
103
|
+
$stdout = StringIO.new
|
104
|
+
end
|
105
|
+
|
106
|
+
teardown do
|
107
|
+
$stdout = STDOUT
|
108
|
+
end
|
109
|
+
|
110
|
+
test 'logs with json' do
|
111
|
+
Resque::Scheduler.log! 'whatever'
|
112
|
+
assert $stdout.string =~ /"msg":"whatever"/
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'logger with text formatter' do
|
117
|
+
setup do
|
118
|
+
nullify_logger
|
119
|
+
Resque::Scheduler.logformat = 'text'
|
120
|
+
$stdout = StringIO.new
|
121
|
+
end
|
122
|
+
|
123
|
+
teardown do
|
124
|
+
$stdout = STDOUT
|
125
|
+
end
|
126
|
+
|
127
|
+
test 'logs with text' do
|
128
|
+
Resque::Scheduler.log! 'another thing'
|
129
|
+
assert $stdout.string =~ /: another thing/
|
93
130
|
end
|
94
131
|
end
|
95
132
|
end
|
data/test/scheduler_task_test.rb
CHANGED
@@ -1,28 +1,33 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
|
-
context
|
4
|
+
context 'Resque::Scheduler' do
|
4
5
|
setup do
|
5
|
-
Resque::Scheduler.
|
6
|
+
Resque::Scheduler.configure do |c|
|
7
|
+
c.dynamic = false
|
8
|
+
c.poll_sleep_amount = 0.1
|
9
|
+
end
|
6
10
|
Resque.redis.flushall
|
7
|
-
Resque::Scheduler.
|
11
|
+
Resque::Scheduler.quiet = true
|
8
12
|
Resque::Scheduler.clear_schedule!
|
9
|
-
Resque::Scheduler.send(:
|
13
|
+
Resque::Scheduler.send(:instance_variable_set, :@scheduled_jobs, {})
|
10
14
|
Resque::Scheduler.send(:instance_variable_set, :@shutdown, false)
|
11
15
|
end
|
12
16
|
|
13
|
-
test
|
17
|
+
test 'shutdown raises Interrupt when sleeping' do
|
14
18
|
Thread.current.expects(:raise).with(Interrupt)
|
15
19
|
Resque::Scheduler.send(:instance_variable_set, :@th, Thread.current)
|
16
20
|
Resque::Scheduler.send(:instance_variable_set, :@sleeping, true)
|
17
21
|
Resque::Scheduler.shutdown
|
18
22
|
end
|
19
23
|
|
20
|
-
test
|
24
|
+
test 'sending TERM to scheduler breaks out of poll_sleep' do
|
21
25
|
Resque::Scheduler.expects(:release_master_lock!)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
|
27
|
+
@pid = Process.pid
|
28
|
+
Thread.new do
|
29
|
+
sleep(0.05)
|
30
|
+
Process.kill(:TERM, @pid)
|
26
31
|
end
|
27
32
|
|
28
33
|
assert_raises SystemExit do
|
data/test/scheduler_test.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
context 'Resque::Scheduler' do
|
4
5
|
setup do
|
5
6
|
Resque::Scheduler.configure do |c|
|
6
7
|
c.dynamic = false
|
7
|
-
c.
|
8
|
+
c.quiet = true
|
8
9
|
c.env = nil
|
9
10
|
c.app_name = nil
|
10
11
|
end
|
11
12
|
Resque.redis.flushall
|
12
13
|
Resque::Scheduler.clear_schedule!
|
13
|
-
Resque::Scheduler.send(:
|
14
|
+
Resque::Scheduler.send(:instance_variable_set, :@scheduled_jobs, {})
|
14
15
|
end
|
15
16
|
|
16
17
|
test 'enqueue constantizes' do
|
@@ -54,45 +55,56 @@ context 'Resque::Scheduler' do
|
|
54
55
|
Resque::Scheduler.enqueue_from_config(config)
|
55
56
|
end
|
56
57
|
|
57
|
-
test
|
58
|
+
test 'config makes it into the rufus_scheduler' do
|
58
59
|
assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
59
60
|
|
60
|
-
Resque.schedule = {
|
61
|
+
Resque.schedule = {
|
62
|
+
some_ivar_job: {
|
63
|
+
'cron' => '* * * * *',
|
64
|
+
'class' => 'SomeIvarJob',
|
65
|
+
'args' => '/tmp'
|
66
|
+
}
|
67
|
+
}
|
61
68
|
Resque::Scheduler.load_schedule!
|
62
69
|
|
63
70
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
64
71
|
assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job')
|
65
72
|
end
|
66
73
|
|
67
|
-
test
|
74
|
+
test 'can reload schedule' do
|
68
75
|
Resque::Scheduler.dynamic = true
|
69
|
-
Resque.schedule = {
|
76
|
+
Resque.schedule = {
|
77
|
+
'some_ivar_job' => {
|
78
|
+
'cron' => '* * * * *',
|
79
|
+
'class' => 'SomeIvarJob',
|
80
|
+
'args' => '/tmp'
|
81
|
+
}
|
82
|
+
}
|
70
83
|
|
71
84
|
Resque::Scheduler.load_schedule!
|
72
85
|
|
73
86
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
74
|
-
assert Resque::Scheduler.scheduled_jobs.include?(
|
87
|
+
assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job')
|
75
88
|
|
76
89
|
Resque.redis.del(:schedules)
|
77
|
-
Resque.redis.hset(:schedules,
|
78
|
-
'cron' =>
|
90
|
+
Resque.redis.hset(:schedules, 'some_ivar_job2', Resque.encode(
|
91
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/2'
|
79
92
|
))
|
80
93
|
|
81
94
|
Resque::Scheduler.reload_schedule!
|
82
95
|
|
83
96
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
84
97
|
|
85
|
-
assert_equal '/tmp/2', Resque.schedule[
|
86
|
-
assert Resque::Scheduler.scheduled_jobs.include?(
|
98
|
+
assert_equal '/tmp/2', Resque.schedule['some_ivar_job2']['args']
|
99
|
+
assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job2')
|
87
100
|
end
|
88
101
|
|
89
102
|
test 'load_schedule_job loads a schedule' do
|
90
103
|
Resque::Scheduler.load_schedule_job(
|
91
|
-
'some_ivar_job',
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
}
|
104
|
+
'some_ivar_job',
|
105
|
+
'cron' => '* * * * *',
|
106
|
+
'class' => 'SomeIvarJob',
|
107
|
+
'args' => '/tmp'
|
96
108
|
)
|
97
109
|
|
98
110
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
@@ -102,11 +114,10 @@ context 'Resque::Scheduler' do
|
|
102
114
|
|
103
115
|
test 'load_schedule_job with every with options' do
|
104
116
|
Resque::Scheduler.load_schedule_job(
|
105
|
-
'some_ivar_job',
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
}
|
117
|
+
'some_ivar_job',
|
118
|
+
'every' => ['30s', { 'first_in' => '60s' }],
|
119
|
+
'class' => 'SomeIvarJob',
|
120
|
+
'args' => '/tmp'
|
110
121
|
)
|
111
122
|
|
112
123
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
@@ -118,11 +129,10 @@ context 'Resque::Scheduler' do
|
|
118
129
|
|
119
130
|
test 'load_schedule_job with cron with options' do
|
120
131
|
Resque::Scheduler.load_schedule_job(
|
121
|
-
'some_ivar_job',
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
}
|
132
|
+
'some_ivar_job',
|
133
|
+
'cron' => ['* * * * *', { 'allow_overlapping' => 'true' }],
|
134
|
+
'class' => 'SomeIvarJob',
|
135
|
+
'args' => '/tmp'
|
126
136
|
)
|
127
137
|
|
128
138
|
assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
@@ -134,10 +144,9 @@ context 'Resque::Scheduler' do
|
|
134
144
|
|
135
145
|
test 'load_schedule_job without cron' do
|
136
146
|
Resque::Scheduler.load_schedule_job(
|
137
|
-
'some_ivar_job',
|
138
|
-
|
139
|
-
|
140
|
-
}
|
147
|
+
'some_ivar_job',
|
148
|
+
'class' => 'SomeIvarJob',
|
149
|
+
'args' => '/tmp'
|
141
150
|
)
|
142
151
|
|
143
152
|
assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
@@ -147,11 +156,10 @@ context 'Resque::Scheduler' do
|
|
147
156
|
|
148
157
|
test 'load_schedule_job with an empty cron' do
|
149
158
|
Resque::Scheduler.load_schedule_job(
|
150
|
-
'some_ivar_job',
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
159
|
+
'some_ivar_job',
|
160
|
+
'cron' => '',
|
161
|
+
'class' => 'SomeIvarJob',
|
162
|
+
'args' => '/tmp'
|
155
163
|
)
|
156
164
|
|
157
165
|
assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
@@ -159,26 +167,35 @@ context 'Resque::Scheduler' do
|
|
159
167
|
assert !Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job')
|
160
168
|
end
|
161
169
|
|
162
|
-
test
|
170
|
+
test 'update_schedule' do
|
163
171
|
Resque::Scheduler.dynamic = true
|
164
172
|
Resque.schedule = {
|
165
|
-
|
166
|
-
|
167
|
-
|
173
|
+
'some_ivar_job' => {
|
174
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp'
|
175
|
+
},
|
176
|
+
'another_ivar_job' => {
|
177
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/5'
|
178
|
+
},
|
179
|
+
'stay_put_job' => {
|
180
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp'
|
181
|
+
}
|
168
182
|
}
|
169
183
|
|
170
184
|
Resque::Scheduler.load_schedule!
|
171
185
|
|
172
|
-
Resque.set_schedule(
|
173
|
-
|
186
|
+
Resque.set_schedule(
|
187
|
+
'some_ivar_job',
|
188
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/2 '
|
174
189
|
)
|
175
|
-
Resque.set_schedule(
|
176
|
-
|
190
|
+
Resque.set_schedule(
|
191
|
+
'new_ivar_job',
|
192
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp/3 '
|
177
193
|
)
|
178
|
-
Resque.set_schedule(
|
179
|
-
|
194
|
+
Resque.set_schedule(
|
195
|
+
'stay_put_job',
|
196
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp '
|
180
197
|
)
|
181
|
-
Resque.remove_schedule(
|
198
|
+
Resque.remove_schedule('another_ivar_job')
|
182
199
|
|
183
200
|
Resque::Scheduler.update_schedule
|
184
201
|
|
@@ -188,34 +205,40 @@ context 'Resque::Scheduler' do
|
|
188
205
|
assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
|
189
206
|
assert Resque.schedule.keys.include?(job_name)
|
190
207
|
end
|
191
|
-
assert !Resque::Scheduler.scheduled_jobs.keys.include?(
|
192
|
-
assert !Resque.schedule.keys.include?(
|
208
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?('another_ivar_job')
|
209
|
+
assert !Resque.schedule.keys.include?('another_ivar_job')
|
193
210
|
assert_equal 0, Resque.redis.scard(:schedules_changed)
|
194
211
|
end
|
195
212
|
|
196
|
-
test
|
213
|
+
test 'update_schedule with mocks' do
|
197
214
|
Resque::Scheduler.dynamic = true
|
198
215
|
Resque.schedule = {
|
199
|
-
|
200
|
-
|
201
|
-
|
216
|
+
'some_ivar_job' => {
|
217
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp'
|
218
|
+
},
|
219
|
+
'another_ivar_job' => {
|
220
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/5'
|
221
|
+
},
|
222
|
+
'stay_put_job' => {
|
223
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp'
|
224
|
+
}
|
202
225
|
}
|
203
226
|
|
204
227
|
Resque::Scheduler.load_schedule!
|
205
228
|
|
206
|
-
Resque
|
207
|
-
|
208
|
-
|
209
|
-
Resque.set_schedule("some_ivar_job",
|
210
|
-
{'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}
|
229
|
+
Resque.set_schedule(
|
230
|
+
'some_ivar_job',
|
231
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/2 '
|
211
232
|
)
|
212
|
-
Resque.set_schedule(
|
213
|
-
|
233
|
+
Resque.set_schedule(
|
234
|
+
'new_ivar_job',
|
235
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp/3 '
|
214
236
|
)
|
215
|
-
Resque.set_schedule(
|
216
|
-
|
237
|
+
Resque.set_schedule(
|
238
|
+
'stay_put_job',
|
239
|
+
'cron' => '* * * * *', 'class' => 'SomeJob', 'args' => '/tmp '
|
217
240
|
)
|
218
|
-
Resque.remove_schedule(
|
241
|
+
Resque.remove_schedule('another_ivar_job')
|
219
242
|
|
220
243
|
Resque::Scheduler.update_schedule
|
221
244
|
|
@@ -224,99 +247,162 @@ context 'Resque::Scheduler' do
|
|
224
247
|
assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
|
225
248
|
assert Resque.schedule.keys.include?(job_name)
|
226
249
|
end
|
227
|
-
assert !Resque::Scheduler.scheduled_jobs.keys.include?(
|
228
|
-
assert !Resque.schedule.keys.include?(
|
250
|
+
assert !Resque::Scheduler.scheduled_jobs.keys.include?('another_ivar_job')
|
251
|
+
assert !Resque.schedule.keys.include?('another_ivar_job')
|
229
252
|
assert_equal 0, Resque.redis.scard(:schedules_changed)
|
230
253
|
end
|
231
254
|
|
232
|
-
test
|
255
|
+
test 'concurrent update_schedule calls' do
|
233
256
|
Resque::Scheduler.dynamic = true
|
234
|
-
Resque.
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
257
|
+
Resque::Scheduler.load_schedule!
|
258
|
+
jobs_count = 100
|
259
|
+
|
260
|
+
background_delayed_update = Thread.new do
|
261
|
+
sleep(0.01)
|
262
|
+
Resque::Scheduler.update_schedule
|
263
|
+
end
|
264
|
+
|
265
|
+
(0...jobs_count).each do |i|
|
266
|
+
Resque.set_schedule(
|
267
|
+
"some_ivar_job#{i}",
|
268
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => "/tmp/#{i}"
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
background_delayed_update.join
|
273
|
+
Resque::Scheduler.update_schedule
|
274
|
+
assert_equal(jobs_count, Resque::Scheduler.rufus_scheduler.all_jobs.size)
|
275
|
+
assert_equal(jobs_count, Resque::Scheduler.scheduled_jobs.size)
|
276
|
+
assert_equal 0, Resque.redis.scard(:schedules_changed)
|
239
277
|
end
|
240
278
|
|
241
|
-
test
|
279
|
+
test 'schedule= sets the schedule' do
|
242
280
|
Resque::Scheduler.dynamic = true
|
281
|
+
Resque.schedule = {
|
282
|
+
'my_ivar_job' => {
|
283
|
+
'cron' => '* * * * *',
|
284
|
+
'class' => 'SomeIvarJob',
|
285
|
+
'args' => '/tmp/75'
|
286
|
+
}
|
287
|
+
}
|
288
|
+
assert_equal(
|
289
|
+
{ 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/75' },
|
290
|
+
Resque.decode(Resque.redis.hget(:schedules, 'my_ivar_job'))
|
291
|
+
)
|
292
|
+
end
|
243
293
|
|
244
|
-
|
245
|
-
|
294
|
+
test 'schedule= removes schedules not present in the given ' \
|
295
|
+
'schedule argument' do
|
296
|
+
Resque::Scheduler.dynamic = true
|
297
|
+
|
298
|
+
Resque.schedule = {
|
299
|
+
'old_job' => { 'cron' => '* * * * *', 'class' => 'OldJob' }
|
300
|
+
}
|
301
|
+
assert_equal(
|
302
|
+
{ 'old_job' => { 'cron' => '* * * * *', 'class' => 'OldJob' } },
|
303
|
+
Resque.schedule
|
304
|
+
)
|
246
305
|
|
247
|
-
Resque.schedule = {
|
306
|
+
Resque.schedule = {
|
307
|
+
'new_job' => { 'cron' => '* * * * *', 'class' => 'NewJob' }
|
308
|
+
}
|
248
309
|
Resque.reload_schedule!
|
249
|
-
assert_equal(
|
310
|
+
assert_equal(
|
311
|
+
{ 'new_job' => { 'cron' => '* * * * *', 'class' => 'NewJob' } },
|
312
|
+
Resque.schedule
|
313
|
+
)
|
250
314
|
end
|
251
315
|
|
252
316
|
test "schedule= uses job name as 'class' argument if it's missing" do
|
253
317
|
Resque::Scheduler.dynamic = true
|
254
|
-
Resque.schedule = {
|
255
|
-
'cron' =>
|
256
|
-
}}
|
257
|
-
assert_equal(
|
258
|
-
|
318
|
+
Resque.schedule = { 'SomeIvarJob' => {
|
319
|
+
'cron' => '* * * * *', 'args' => '/tmp/75'
|
320
|
+
} }
|
321
|
+
assert_equal(
|
322
|
+
{ 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/75' },
|
323
|
+
Resque.decode(Resque.redis.hget(:schedules, 'SomeIvarJob'))
|
324
|
+
)
|
259
325
|
assert_equal('SomeIvarJob', Resque.schedule['SomeIvarJob']['class'])
|
260
326
|
end
|
261
327
|
|
262
|
-
test
|
263
|
-
schedule = {
|
264
|
-
'cron' =>
|
265
|
-
}}
|
328
|
+
test 'schedule= does not mutate argument' do
|
329
|
+
schedule = { 'SomeIvarJob' => {
|
330
|
+
'cron' => '* * * * *', 'args' => '/tmp/75'
|
331
|
+
} }
|
266
332
|
Resque.schedule = schedule
|
267
333
|
assert !schedule['SomeIvarJob'].key?('class')
|
268
334
|
end
|
269
335
|
|
270
|
-
test
|
271
|
-
Resque.set_schedule(
|
272
|
-
'
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
336
|
+
test 'set_schedule can set an individual schedule' do
|
337
|
+
Resque.set_schedule(
|
338
|
+
'some_ivar_job',
|
339
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/22'
|
340
|
+
)
|
341
|
+
assert_equal(
|
342
|
+
{ 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/22' },
|
343
|
+
Resque.decode(Resque.redis.hget(:schedules, 'some_ivar_job'))
|
344
|
+
)
|
345
|
+
assert Resque.redis.sismember(:schedules_changed, 'some_ivar_job')
|
277
346
|
end
|
278
347
|
|
279
|
-
test
|
280
|
-
Resque.redis.hset(:schedules,
|
281
|
-
'cron' =>
|
348
|
+
test 'fetch_schedule returns a schedule' do
|
349
|
+
Resque.redis.hset(:schedules, 'some_ivar_job2', Resque.encode(
|
350
|
+
'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/33'
|
282
351
|
))
|
283
|
-
assert_equal(
|
284
|
-
|
352
|
+
assert_equal(
|
353
|
+
{ 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/33' },
|
354
|
+
Resque.fetch_schedule('some_ivar_job2')
|
355
|
+
)
|
285
356
|
end
|
286
357
|
|
287
|
-
test
|
288
|
-
Resque.set_schedule(
|
289
|
-
|
358
|
+
test 'remove_schedule removes a schedule' do
|
359
|
+
Resque.set_schedule(
|
360
|
+
'some_ivar_job3',
|
361
|
+
'cron' => '* * * * *',
|
362
|
+
'class' => 'SomeIvarJob',
|
363
|
+
'args' => '/tmp/44',
|
364
|
+
'persist' => true
|
290
365
|
)
|
291
366
|
Resque::Scheduler.load_schedule!
|
292
|
-
Resque.remove_schedule(
|
293
|
-
assert_equal nil, Resque.redis.hget(:schedules,
|
294
|
-
assert Resque.redis.sismember(:schedules_changed,
|
367
|
+
Resque.remove_schedule('some_ivar_job3')
|
368
|
+
assert_equal nil, Resque.redis.hget(:schedules, 'some_ivar_job3')
|
369
|
+
assert Resque.redis.sismember(:schedules_changed, 'some_ivar_job3')
|
295
370
|
assert_equal [], Resque.redis.smembers(:persisted_schedules)
|
296
371
|
end
|
297
372
|
|
298
|
-
test
|
299
|
-
Resque.set_schedule(
|
300
|
-
|
373
|
+
test 'persisted schedules' do
|
374
|
+
Resque.set_schedule(
|
375
|
+
'some_ivar_job',
|
376
|
+
'cron' => '* * * * *',
|
377
|
+
'class' => 'SomeIvarJob',
|
378
|
+
'args' => '/tmp/2',
|
379
|
+
'persist' => true
|
301
380
|
)
|
302
|
-
Resque.set_schedule(
|
303
|
-
|
381
|
+
Resque.set_schedule(
|
382
|
+
'new_ivar_job',
|
383
|
+
'cron' => '* * * * *',
|
384
|
+
'class' => 'SomeJob',
|
385
|
+
'args' => '/tmp/3 '
|
304
386
|
)
|
305
387
|
|
306
|
-
Resque.schedule=
|
307
|
-
'a_schedule' => {
|
308
|
-
|
388
|
+
Resque.schedule = {
|
389
|
+
'a_schedule' => {
|
390
|
+
'cron' => '* * * * *', 'class' => 'SomeOtherJob', 'args' => '/tmp'
|
391
|
+
}
|
392
|
+
}
|
309
393
|
Resque::Scheduler.load_schedule!
|
310
394
|
|
311
|
-
assert_equal(
|
312
|
-
|
395
|
+
assert_equal(
|
396
|
+
{ 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp/2' },
|
397
|
+
Resque.schedule['some_ivar_job']
|
398
|
+
)
|
313
399
|
assert_equal(nil, Resque.schedule['some_job'])
|
314
400
|
end
|
315
401
|
|
316
|
-
test
|
402
|
+
test 'adheres to lint' do
|
317
403
|
assert_nothing_raised do
|
318
404
|
Resque::Plugin.lint(Resque::Scheduler)
|
319
|
-
Resque::Plugin.lint(
|
405
|
+
Resque::Plugin.lint(Resque::Scheduler::Extension)
|
320
406
|
end
|
321
407
|
end
|
322
408
|
|
@@ -341,4 +427,19 @@ context 'Resque::Scheduler' do
|
|
341
427
|
assert Resque::Scheduler.send(:build_procline, 'cage') =~
|
342
428
|
/#{Resque::Scheduler.send(:internal_name)}: cage/
|
343
429
|
end
|
430
|
+
|
431
|
+
context 'printing schedule' do
|
432
|
+
setup do
|
433
|
+
Resque::Scheduler.expects(:log!).at_least_once
|
434
|
+
end
|
435
|
+
|
436
|
+
test 'prints schedule' do
|
437
|
+
fake_rufus_scheduler = mock
|
438
|
+
fake_rufus_scheduler.expects(:all_jobs).at_least_once
|
439
|
+
.returns(foo: OpenStruct.new(t: nil, last: nil))
|
440
|
+
Resque::Scheduler.expects(:rufus_scheduler).at_least_once
|
441
|
+
.returns(fake_rufus_scheduler)
|
442
|
+
Resque::Scheduler.print_schedule
|
443
|
+
end
|
444
|
+
end
|
344
445
|
end
|