resque 1.23.0 → 2.6.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.
- checksums.yaml +7 -0
- data/HISTORY.md +271 -0
- data/README.markdown +454 -484
- data/Rakefile +4 -17
- data/bin/resque-web +10 -22
- data/lib/resque/data_store.rb +335 -0
- data/lib/resque/errors.rb +15 -1
- data/lib/resque/failure/airbrake.rb +32 -4
- data/lib/resque/failure/base.rb +16 -7
- data/lib/resque/failure/multiple.rb +26 -8
- data/lib/resque/failure/redis.rb +92 -15
- data/lib/resque/failure/redis_multi_queue.rb +104 -0
- data/lib/resque/failure.rb +62 -32
- data/lib/resque/helpers.rb +11 -57
- data/lib/resque/job.rb +79 -12
- data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
- data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
- data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
- data/lib/resque/logging.rb +18 -0
- data/lib/resque/plugin.rb +22 -10
- data/lib/resque/railtie.rb +10 -0
- data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
- data/lib/resque/server/public/jquery.relatize_date.js +4 -4
- data/lib/resque/server/public/main.js +3 -0
- data/lib/resque/server/public/ranger.js +16 -8
- data/lib/resque/server/public/style.css +13 -8
- data/lib/resque/server/views/error.erb +1 -1
- data/lib/resque/server/views/failed.erb +27 -59
- data/lib/resque/server/views/failed_job.erb +50 -0
- data/lib/resque/server/views/failed_queues_overview.erb +24 -0
- data/lib/resque/server/views/job_class.erb +8 -0
- data/lib/resque/server/views/key_sets.erb +2 -4
- data/lib/resque/server/views/key_string.erb +1 -1
- data/lib/resque/server/views/layout.erb +7 -6
- data/lib/resque/server/views/next_more.erb +22 -10
- data/lib/resque/server/views/processing.erb +2 -0
- data/lib/resque/server/views/queues.erb +22 -13
- data/lib/resque/server/views/stats.erb +5 -5
- data/lib/resque/server/views/workers.erb +4 -4
- data/lib/resque/server/views/working.erb +10 -11
- data/lib/resque/server.rb +51 -108
- data/lib/resque/server_helper.rb +185 -0
- data/lib/resque/stat.rb +19 -7
- data/lib/resque/tasks.rb +26 -25
- data/lib/resque/thread_signal.rb +24 -0
- data/lib/resque/vendor/utf8_util.rb +2 -8
- data/lib/resque/version.rb +1 -1
- data/lib/resque/web_runner.rb +374 -0
- data/lib/resque/worker.rb +487 -163
- data/lib/resque.rb +332 -52
- data/lib/tasks/redis.rake +11 -11
- metadata +169 -149
- data/lib/resque/failure/hoptoad.rb +0 -33
- data/lib/resque/failure/thoughtbot.rb +0 -33
- data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
- data/lib/resque/server/test_helper.rb +0 -19
- data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
- data/test/airbrake_test.rb +0 -27
- data/test/hoptoad_test.rb +0 -26
- data/test/job_hooks_test.rb +0 -464
- data/test/job_plugins_test.rb +0 -230
- data/test/plugin_test.rb +0 -116
- data/test/redis-test-cluster.conf +0 -115
- data/test/redis-test.conf +0 -115
- data/test/resque-web_test.rb +0 -59
- data/test/resque_failure_redis_test.rb +0 -19
- data/test/resque_test.rb +0 -278
- data/test/test_helper.rb +0 -178
- data/test/worker_test.rb +0 -657
data/test/worker_test.rb
DELETED
@@ -1,657 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
context "Resque::Worker" do
|
4
|
-
setup do
|
5
|
-
Resque.redis.flushall
|
6
|
-
|
7
|
-
Resque.before_first_fork = nil
|
8
|
-
Resque.before_fork = nil
|
9
|
-
Resque.after_fork = nil
|
10
|
-
|
11
|
-
@worker = Resque::Worker.new(:jobs)
|
12
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
13
|
-
end
|
14
|
-
|
15
|
-
test "can fail jobs" do
|
16
|
-
Resque::Job.create(:jobs, BadJob)
|
17
|
-
@worker.work(0)
|
18
|
-
assert_equal 1, Resque::Failure.count
|
19
|
-
end
|
20
|
-
|
21
|
-
test "failed jobs report exception and message" do
|
22
|
-
Resque::Job.create(:jobs, BadJobWithSyntaxError)
|
23
|
-
@worker.work(0)
|
24
|
-
assert_equal('SyntaxError', Resque::Failure.all['exception'])
|
25
|
-
assert_equal('Extra Bad job!', Resque::Failure.all['error'])
|
26
|
-
end
|
27
|
-
|
28
|
-
test "does not allow exceptions from failure backend to escape" do
|
29
|
-
job = Resque::Job.new(:jobs, {})
|
30
|
-
with_failure_backend BadFailureBackend do
|
31
|
-
@worker.perform job
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
test "fails uncompleted jobs with DirtyExit by default on exit" do
|
36
|
-
job = Resque::Job.new(:jobs, {'class' => 'GoodJob', 'args' => "blah"})
|
37
|
-
@worker.working_on(job)
|
38
|
-
@worker.unregister_worker
|
39
|
-
assert_equal 1, Resque::Failure.count
|
40
|
-
assert_equal('Resque::DirtyExit', Resque::Failure.all['exception'])
|
41
|
-
end
|
42
|
-
|
43
|
-
test "fails uncompleted jobs with worker exception on exit" do
|
44
|
-
job = Resque::Job.new(:jobs, {'class' => 'GoodJob', 'args' => "blah"})
|
45
|
-
@worker.working_on(job)
|
46
|
-
@worker.unregister_worker(StandardError.new)
|
47
|
-
assert_equal 1, Resque::Failure.count
|
48
|
-
assert_equal('StandardError', Resque::Failure.all['exception'])
|
49
|
-
end
|
50
|
-
|
51
|
-
class ::SimpleJobWithFailureHandling
|
52
|
-
def self.on_failure_record_failure(exception, *job_args)
|
53
|
-
@@exception = exception
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.exception
|
57
|
-
@@exception
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
test "fails uncompleted jobs on exit, and calls failure hook" do
|
62
|
-
job = Resque::Job.new(:jobs, {'class' => 'SimpleJobWithFailureHandling', 'args' => ""})
|
63
|
-
@worker.working_on(job)
|
64
|
-
@worker.unregister_worker
|
65
|
-
assert_equal 1, Resque::Failure.count
|
66
|
-
assert(SimpleJobWithFailureHandling.exception.kind_of?(Resque::DirtyExit))
|
67
|
-
end
|
68
|
-
|
69
|
-
class ::SimpleFailingJob
|
70
|
-
@@exception_count = 0
|
71
|
-
|
72
|
-
def self.on_failure_record_failure(exception, *job_args)
|
73
|
-
@@exception_count += 1
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.exception_count
|
77
|
-
@@exception_count
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.perform
|
81
|
-
raise Exception.new
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
test "only calls failure hook once on exception" do
|
86
|
-
job = Resque::Job.new(:jobs, {'class' => 'SimpleFailingJob', 'args' => ""})
|
87
|
-
@worker.perform(job)
|
88
|
-
assert_equal 1, Resque::Failure.count
|
89
|
-
assert_equal 1, SimpleFailingJob.exception_count
|
90
|
-
end
|
91
|
-
|
92
|
-
test "can peek at failed jobs" do
|
93
|
-
10.times { Resque::Job.create(:jobs, BadJob) }
|
94
|
-
@worker.work(0)
|
95
|
-
assert_equal 10, Resque::Failure.count
|
96
|
-
|
97
|
-
assert_equal 10, Resque::Failure.all(0, 20).size
|
98
|
-
end
|
99
|
-
|
100
|
-
test "can clear failed jobs" do
|
101
|
-
Resque::Job.create(:jobs, BadJob)
|
102
|
-
@worker.work(0)
|
103
|
-
assert_equal 1, Resque::Failure.count
|
104
|
-
Resque::Failure.clear
|
105
|
-
assert_equal 0, Resque::Failure.count
|
106
|
-
end
|
107
|
-
|
108
|
-
test "catches exceptional jobs" do
|
109
|
-
Resque::Job.create(:jobs, BadJob)
|
110
|
-
Resque::Job.create(:jobs, BadJob)
|
111
|
-
@worker.process
|
112
|
-
@worker.process
|
113
|
-
@worker.process
|
114
|
-
assert_equal 2, Resque::Failure.count
|
115
|
-
end
|
116
|
-
|
117
|
-
test "strips whitespace from queue names" do
|
118
|
-
queues = "critical, high, low".split(',')
|
119
|
-
worker = Resque::Worker.new(*queues)
|
120
|
-
assert_equal %w( critical high low ), worker.queues
|
121
|
-
end
|
122
|
-
|
123
|
-
test "can work on multiple queues" do
|
124
|
-
Resque::Job.create(:high, GoodJob)
|
125
|
-
Resque::Job.create(:critical, GoodJob)
|
126
|
-
|
127
|
-
worker = Resque::Worker.new(:critical, :high)
|
128
|
-
|
129
|
-
worker.process
|
130
|
-
assert_equal 1, Resque.size(:high)
|
131
|
-
assert_equal 0, Resque.size(:critical)
|
132
|
-
|
133
|
-
worker.process
|
134
|
-
assert_equal 0, Resque.size(:high)
|
135
|
-
end
|
136
|
-
|
137
|
-
test "can work on all queues" do
|
138
|
-
Resque::Job.create(:high, GoodJob)
|
139
|
-
Resque::Job.create(:critical, GoodJob)
|
140
|
-
Resque::Job.create(:blahblah, GoodJob)
|
141
|
-
|
142
|
-
worker = Resque::Worker.new("*")
|
143
|
-
|
144
|
-
worker.work(0)
|
145
|
-
assert_equal 0, Resque.size(:high)
|
146
|
-
assert_equal 0, Resque.size(:critical)
|
147
|
-
assert_equal 0, Resque.size(:blahblah)
|
148
|
-
end
|
149
|
-
|
150
|
-
test "can work with wildcard at the end of the list" do
|
151
|
-
Resque::Job.create(:high, GoodJob)
|
152
|
-
Resque::Job.create(:critical, GoodJob)
|
153
|
-
Resque::Job.create(:blahblah, GoodJob)
|
154
|
-
Resque::Job.create(:beer, GoodJob)
|
155
|
-
|
156
|
-
worker = Resque::Worker.new(:critical, :high, "*")
|
157
|
-
|
158
|
-
worker.work(0)
|
159
|
-
assert_equal 0, Resque.size(:high)
|
160
|
-
assert_equal 0, Resque.size(:critical)
|
161
|
-
assert_equal 0, Resque.size(:blahblah)
|
162
|
-
assert_equal 0, Resque.size(:beer)
|
163
|
-
end
|
164
|
-
|
165
|
-
test "can work with wildcard at the middle of the list" do
|
166
|
-
Resque::Job.create(:high, GoodJob)
|
167
|
-
Resque::Job.create(:critical, GoodJob)
|
168
|
-
Resque::Job.create(:blahblah, GoodJob)
|
169
|
-
Resque::Job.create(:beer, GoodJob)
|
170
|
-
|
171
|
-
worker = Resque::Worker.new(:critical, "*", :high)
|
172
|
-
|
173
|
-
worker.work(0)
|
174
|
-
assert_equal 0, Resque.size(:high)
|
175
|
-
assert_equal 0, Resque.size(:critical)
|
176
|
-
assert_equal 0, Resque.size(:blahblah)
|
177
|
-
assert_equal 0, Resque.size(:beer)
|
178
|
-
end
|
179
|
-
|
180
|
-
test "processes * queues in alphabetical order" do
|
181
|
-
Resque::Job.create(:high, GoodJob)
|
182
|
-
Resque::Job.create(:critical, GoodJob)
|
183
|
-
Resque::Job.create(:blahblah, GoodJob)
|
184
|
-
|
185
|
-
worker = Resque::Worker.new("*")
|
186
|
-
processed_queues = []
|
187
|
-
|
188
|
-
worker.work(0) do |job|
|
189
|
-
processed_queues << job.queue
|
190
|
-
end
|
191
|
-
|
192
|
-
assert_equal %w( jobs high critical blahblah ).sort, processed_queues
|
193
|
-
end
|
194
|
-
|
195
|
-
test "has a unique id" do
|
196
|
-
assert_equal "#{`hostname`.chomp}:#{$$}:jobs", @worker.to_s
|
197
|
-
end
|
198
|
-
|
199
|
-
test "complains if no queues are given" do
|
200
|
-
assert_raise Resque::NoQueueError do
|
201
|
-
Resque::Worker.new
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
test "fails if a job class has no `perform` method" do
|
206
|
-
worker = Resque::Worker.new(:perform_less)
|
207
|
-
Resque::Job.create(:perform_less, Object)
|
208
|
-
|
209
|
-
assert_equal 0, Resque::Failure.count
|
210
|
-
worker.work(0)
|
211
|
-
assert_equal 1, Resque::Failure.count
|
212
|
-
end
|
213
|
-
|
214
|
-
test "inserts itself into the 'workers' list on startup" do
|
215
|
-
@worker.work(0) do
|
216
|
-
assert_equal @worker, Resque.workers[0]
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
test "removes itself from the 'workers' list on shutdown" do
|
221
|
-
@worker.work(0) do
|
222
|
-
assert_equal @worker, Resque.workers[0]
|
223
|
-
end
|
224
|
-
|
225
|
-
assert_equal [], Resque.workers
|
226
|
-
end
|
227
|
-
|
228
|
-
test "removes worker with stringified id" do
|
229
|
-
@worker.work(0) do
|
230
|
-
worker_id = Resque.workers[0].to_s
|
231
|
-
Resque.remove_worker(worker_id)
|
232
|
-
assert_equal [], Resque.workers
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
test "records what it is working on" do
|
237
|
-
@worker.work(0) do
|
238
|
-
task = @worker.job
|
239
|
-
assert_equal({"args"=>[20, "/tmp"], "class"=>"SomeJob"}, task['payload'])
|
240
|
-
assert task['run_at']
|
241
|
-
assert_equal 'jobs', task['queue']
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
test "clears its status when not working on anything" do
|
246
|
-
@worker.work(0)
|
247
|
-
assert_equal Hash.new, @worker.job
|
248
|
-
end
|
249
|
-
|
250
|
-
test "knows when it is working" do
|
251
|
-
@worker.work(0) do
|
252
|
-
assert @worker.working?
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
test "knows when it is idle" do
|
257
|
-
@worker.work(0)
|
258
|
-
assert @worker.idle?
|
259
|
-
end
|
260
|
-
|
261
|
-
test "knows who is working" do
|
262
|
-
@worker.work(0) do
|
263
|
-
assert_equal [@worker], Resque.working
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
test "keeps track of how many jobs it has processed" do
|
268
|
-
Resque::Job.create(:jobs, BadJob)
|
269
|
-
Resque::Job.create(:jobs, BadJob)
|
270
|
-
|
271
|
-
3.times do
|
272
|
-
job = @worker.reserve
|
273
|
-
@worker.process job
|
274
|
-
end
|
275
|
-
assert_equal 3, @worker.processed
|
276
|
-
end
|
277
|
-
|
278
|
-
test "keeps track of how many failures it has seen" do
|
279
|
-
Resque::Job.create(:jobs, BadJob)
|
280
|
-
Resque::Job.create(:jobs, BadJob)
|
281
|
-
|
282
|
-
3.times do
|
283
|
-
job = @worker.reserve
|
284
|
-
@worker.process job
|
285
|
-
end
|
286
|
-
assert_equal 2, @worker.failed
|
287
|
-
end
|
288
|
-
|
289
|
-
test "stats are erased when the worker goes away" do
|
290
|
-
@worker.work(0)
|
291
|
-
assert_equal 0, @worker.processed
|
292
|
-
assert_equal 0, @worker.failed
|
293
|
-
end
|
294
|
-
|
295
|
-
test "knows when it started" do
|
296
|
-
time = Time.now
|
297
|
-
@worker.work(0) do
|
298
|
-
assert Time.parse(@worker.started) - time < 0.1
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
test "knows whether it exists or not" do
|
303
|
-
@worker.work(0) do
|
304
|
-
assert Resque::Worker.exists?(@worker)
|
305
|
-
assert !Resque::Worker.exists?('blah-blah')
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
test "sets $0 while working" do
|
310
|
-
@worker.work(0) do
|
311
|
-
ver = Resque::Version
|
312
|
-
assert_equal "resque-#{ver}: Processing jobs since #{Time.now.to_i}", $0
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
test "can be found" do
|
317
|
-
@worker.work(0) do
|
318
|
-
found = Resque::Worker.find(@worker.to_s)
|
319
|
-
assert_equal @worker.to_s, found.to_s
|
320
|
-
assert found.working?
|
321
|
-
assert_equal @worker.job, found.job
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
test "doesn't find fakes" do
|
326
|
-
@worker.work(0) do
|
327
|
-
found = Resque::Worker.find('blah-blah')
|
328
|
-
assert_equal nil, found
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
test "cleans up dead worker info on start (crash recovery)" do
|
333
|
-
# first we fake out two dead workers
|
334
|
-
workerA = Resque::Worker.new(:jobs)
|
335
|
-
workerA.instance_variable_set(:@to_s, "#{`hostname`.chomp}:1:jobs")
|
336
|
-
workerA.register_worker
|
337
|
-
|
338
|
-
workerB = Resque::Worker.new(:high, :low)
|
339
|
-
workerB.instance_variable_set(:@to_s, "#{`hostname`.chomp}:2:high,low")
|
340
|
-
workerB.register_worker
|
341
|
-
|
342
|
-
assert_equal 2, Resque.workers.size
|
343
|
-
|
344
|
-
# then we prune them
|
345
|
-
@worker.work(0) do
|
346
|
-
assert_equal 1, Resque.workers.size
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
test "worker_pids returns pids" do
|
351
|
-
known_workers = @worker.worker_pids
|
352
|
-
assert !known_workers.empty?
|
353
|
-
end
|
354
|
-
|
355
|
-
test "Processed jobs count" do
|
356
|
-
@worker.work(0)
|
357
|
-
assert_equal 1, Resque.info[:processed]
|
358
|
-
end
|
359
|
-
|
360
|
-
test "Will call a before_first_fork hook only once" do
|
361
|
-
Resque.redis.flushall
|
362
|
-
$BEFORE_FORK_CALLED = 0
|
363
|
-
Resque.before_first_fork = Proc.new { $BEFORE_FORK_CALLED += 1 }
|
364
|
-
workerA = Resque::Worker.new(:jobs)
|
365
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
366
|
-
|
367
|
-
assert_equal 0, $BEFORE_FORK_CALLED
|
368
|
-
|
369
|
-
workerA.work(0)
|
370
|
-
assert_equal 1, $BEFORE_FORK_CALLED
|
371
|
-
|
372
|
-
# TODO: Verify it's only run once. Not easy.
|
373
|
-
# workerA.work(0)
|
374
|
-
# assert_equal 1, $BEFORE_FORK_CALLED
|
375
|
-
end
|
376
|
-
|
377
|
-
test "Will call a before_fork hook before forking" do
|
378
|
-
Resque.redis.flushall
|
379
|
-
$BEFORE_FORK_CALLED = false
|
380
|
-
Resque.before_fork = Proc.new { $BEFORE_FORK_CALLED = true }
|
381
|
-
workerA = Resque::Worker.new(:jobs)
|
382
|
-
|
383
|
-
assert !$BEFORE_FORK_CALLED
|
384
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
385
|
-
workerA.work(0)
|
386
|
-
assert $BEFORE_FORK_CALLED
|
387
|
-
end
|
388
|
-
|
389
|
-
test "Will not call a before_fork hook when the worker can't fork" do
|
390
|
-
Resque.redis.flushall
|
391
|
-
$BEFORE_FORK_CALLED = false
|
392
|
-
Resque.before_fork = Proc.new { $BEFORE_FORK_CALLED = true }
|
393
|
-
workerA = Resque::Worker.new(:jobs)
|
394
|
-
workerA.cant_fork = true
|
395
|
-
|
396
|
-
assert !$BEFORE_FORK_CALLED, "before_fork should not have been called before job runs"
|
397
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
398
|
-
workerA.work(0)
|
399
|
-
assert !$BEFORE_FORK_CALLED, "before_fork should not have been called after job runs"
|
400
|
-
end
|
401
|
-
|
402
|
-
test "very verbose works in the afternoon" do
|
403
|
-
begin
|
404
|
-
require 'time'
|
405
|
-
last_puts = ""
|
406
|
-
Time.fake_time = Time.parse("15:44:33 2011-03-02")
|
407
|
-
|
408
|
-
@worker.extend(Module.new {
|
409
|
-
define_method(:puts) { |thing| last_puts = thing }
|
410
|
-
})
|
411
|
-
|
412
|
-
@worker.very_verbose = true
|
413
|
-
@worker.log("some log text")
|
414
|
-
|
415
|
-
assert_match /\*\* \[15:44:33 2011-03-02\] \d+: some log text/, last_puts
|
416
|
-
ensure
|
417
|
-
Time.fake_time = nil
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
test "Will call an after_fork hook if we're forking" do
|
422
|
-
Resque.redis.flushall
|
423
|
-
$AFTER_FORK_CALLED = false
|
424
|
-
Resque.after_fork = Proc.new { $AFTER_FORK_CALLED = true }
|
425
|
-
workerA = Resque::Worker.new(:jobs)
|
426
|
-
|
427
|
-
assert !$AFTER_FORK_CALLED
|
428
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
429
|
-
workerA.work(0)
|
430
|
-
assert $AFTER_FORK_CALLED == workerA.will_fork?
|
431
|
-
end
|
432
|
-
|
433
|
-
test "Will not call an after_fork hook when the worker can't fork" do
|
434
|
-
Resque.redis.flushall
|
435
|
-
$AFTER_FORK_CALLED = false
|
436
|
-
Resque.after_fork = Proc.new { $AFTER_FORK_CALLED = true }
|
437
|
-
workerA = Resque::Worker.new(:jobs)
|
438
|
-
workerA.cant_fork = true
|
439
|
-
|
440
|
-
assert !$AFTER_FORK_CALLED
|
441
|
-
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
442
|
-
workerA.work(0)
|
443
|
-
assert !$AFTER_FORK_CALLED
|
444
|
-
end
|
445
|
-
|
446
|
-
test "returns PID of running process" do
|
447
|
-
assert_equal @worker.to_s.split(":")[1].to_i, @worker.pid
|
448
|
-
end
|
449
|
-
|
450
|
-
test "requeue failed queue" do
|
451
|
-
queue = 'good_job'
|
452
|
-
Resque::Failure.create(:exception => Exception.new, :worker => Resque::Worker.new(queue), :queue => queue, :payload => {'class' => 'GoodJob'})
|
453
|
-
Resque::Failure.create(:exception => Exception.new, :worker => Resque::Worker.new(queue), :queue => 'some_job', :payload => {'class' => 'SomeJob'})
|
454
|
-
Resque::Failure.requeue_queue(queue)
|
455
|
-
assert Resque::Failure.all(0).has_key?('retried_at')
|
456
|
-
assert !Resque::Failure.all(1).has_key?('retried_at')
|
457
|
-
end
|
458
|
-
|
459
|
-
test "remove failed queue" do
|
460
|
-
queue = 'good_job'
|
461
|
-
queue2 = 'some_job'
|
462
|
-
Resque::Failure.create(:exception => Exception.new, :worker => Resque::Worker.new(queue), :queue => queue, :payload => {'class' => 'GoodJob'})
|
463
|
-
Resque::Failure.create(:exception => Exception.new, :worker => Resque::Worker.new(queue2), :queue => queue2, :payload => {'class' => 'SomeJob'})
|
464
|
-
Resque::Failure.create(:exception => Exception.new, :worker => Resque::Worker.new(queue), :queue => queue, :payload => {'class' => 'GoodJob'})
|
465
|
-
Resque::Failure.remove_queue(queue)
|
466
|
-
assert_equal queue2, Resque::Failure.all(0)['queue']
|
467
|
-
assert_equal 1, Resque::Failure.count
|
468
|
-
end
|
469
|
-
|
470
|
-
test "reconnects to redis after fork" do
|
471
|
-
original_connection = Resque.redis.client.connection.instance_variable_get("@sock")
|
472
|
-
@worker.work(0)
|
473
|
-
assert_not_equal original_connection, Resque.redis.client.connection.instance_variable_get("@sock")
|
474
|
-
end
|
475
|
-
|
476
|
-
test "tries to reconnect three times before giving up" do
|
477
|
-
begin
|
478
|
-
class Redis::Client
|
479
|
-
alias_method :original_reconnect, :reconnect
|
480
|
-
|
481
|
-
def reconnect
|
482
|
-
raise Redis::BaseConnectionError
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
class Resque::Worker
|
487
|
-
alias_method :original_sleep, :sleep
|
488
|
-
|
489
|
-
def sleep(duration = nil)
|
490
|
-
# noop
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
@worker.very_verbose = true
|
495
|
-
stdout, stderr = capture_io { @worker.work(0) }
|
496
|
-
|
497
|
-
assert_equal 3, stdout.scan(/retrying/).count
|
498
|
-
assert_equal 1, stdout.scan(/quitting/).count
|
499
|
-
ensure
|
500
|
-
class Redis::Client
|
501
|
-
alias_method :reconnect, :original_reconnect
|
502
|
-
end
|
503
|
-
|
504
|
-
class Resque::Worker
|
505
|
-
alias_method :sleep, :original_sleep
|
506
|
-
end
|
507
|
-
end
|
508
|
-
end
|
509
|
-
|
510
|
-
if !defined?(RUBY_ENGINE) || defined?(RUBY_ENGINE) && RUBY_ENGINE != "jruby"
|
511
|
-
test "old signal handling is the default" do
|
512
|
-
rescue_time = nil
|
513
|
-
|
514
|
-
begin
|
515
|
-
class LongRunningJob
|
516
|
-
@queue = :long_running_job
|
517
|
-
|
518
|
-
def self.perform( run_time, rescue_time=nil )
|
519
|
-
Resque.redis.client.reconnect # get its own connection
|
520
|
-
Resque.redis.rpush( 'sigterm-test:start', Process.pid )
|
521
|
-
sleep run_time
|
522
|
-
Resque.redis.rpush( 'sigterm-test:result', 'Finished Normally' )
|
523
|
-
rescue Resque::TermException => e
|
524
|
-
Resque.redis.rpush( 'sigterm-test:result', %Q(Caught SignalException: #{e.inspect}))
|
525
|
-
sleep rescue_time unless rescue_time.nil?
|
526
|
-
ensure
|
527
|
-
puts 'fuuuu'
|
528
|
-
Resque.redis.rpush( 'sigterm-test:final', 'exiting.' )
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
Resque.enqueue( LongRunningJob, 5, rescue_time )
|
533
|
-
|
534
|
-
worker_pid = Kernel.fork do
|
535
|
-
# ensure we actually fork
|
536
|
-
$TESTING = false
|
537
|
-
# reconnect since we just forked
|
538
|
-
Resque.redis.client.reconnect
|
539
|
-
|
540
|
-
worker = Resque::Worker.new(:long_running_job)
|
541
|
-
|
542
|
-
worker.work(0)
|
543
|
-
exit!
|
544
|
-
end
|
545
|
-
|
546
|
-
# ensure the worker is started
|
547
|
-
start_status = Resque.redis.blpop( 'sigterm-test:start', 5 )
|
548
|
-
assert_not_nil start_status
|
549
|
-
child_pid = start_status[1].to_i
|
550
|
-
assert_operator child_pid, :>, 0
|
551
|
-
|
552
|
-
# send signal to abort the worker
|
553
|
-
Process.kill('TERM', worker_pid)
|
554
|
-
Process.waitpid(worker_pid)
|
555
|
-
|
556
|
-
# wait to see how it all came down
|
557
|
-
result = Resque.redis.blpop( 'sigterm-test:result', 5 )
|
558
|
-
assert_nil result
|
559
|
-
|
560
|
-
# ensure that the child pid is no longer running
|
561
|
-
child_still_running = !(`ps -p #{child_pid.to_s} -o pid=`).empty?
|
562
|
-
assert !child_still_running
|
563
|
-
ensure
|
564
|
-
remaining_keys = Resque.redis.keys('sigterm-test:*') || []
|
565
|
-
Resque.redis.del(*remaining_keys) unless remaining_keys.empty?
|
566
|
-
end
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
if !defined?(RUBY_ENGINE) || defined?(RUBY_ENGINE) && RUBY_ENGINE != "jruby"
|
571
|
-
[SignalException, Resque::TermException].each do |exception|
|
572
|
-
{
|
573
|
-
'cleanup occurs in allotted time' => nil,
|
574
|
-
'cleanup takes too long' => 2
|
575
|
-
}.each do |scenario,rescue_time|
|
576
|
-
test "SIGTERM when #{scenario} while catching #{exception}" do
|
577
|
-
begin
|
578
|
-
eval("class LongRunningJob; @@exception = #{exception}; end")
|
579
|
-
class LongRunningJob
|
580
|
-
@queue = :long_running_job
|
581
|
-
|
582
|
-
def self.perform( run_time, rescue_time=nil )
|
583
|
-
Resque.redis.client.reconnect # get its own connection
|
584
|
-
Resque.redis.rpush( 'sigterm-test:start', Process.pid )
|
585
|
-
sleep run_time
|
586
|
-
Resque.redis.rpush( 'sigterm-test:result', 'Finished Normally' )
|
587
|
-
rescue @@exception => e
|
588
|
-
Resque.redis.rpush( 'sigterm-test:result', %Q(Caught SignalException: #{e.inspect}))
|
589
|
-
sleep rescue_time unless rescue_time.nil?
|
590
|
-
ensure
|
591
|
-
Resque.redis.rpush( 'sigterm-test:final', 'exiting.' )
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
Resque.enqueue( LongRunningJob, 5, rescue_time )
|
596
|
-
|
597
|
-
worker_pid = Kernel.fork do
|
598
|
-
# ensure we actually fork
|
599
|
-
$TESTING = false
|
600
|
-
# reconnect since we just forked
|
601
|
-
Resque.redis.client.reconnect
|
602
|
-
|
603
|
-
worker = Resque::Worker.new(:long_running_job)
|
604
|
-
worker.term_timeout = 1
|
605
|
-
worker.term_child = 1
|
606
|
-
|
607
|
-
worker.work(0)
|
608
|
-
exit!
|
609
|
-
end
|
610
|
-
|
611
|
-
# ensure the worker is started
|
612
|
-
start_status = Resque.redis.blpop( 'sigterm-test:start', 5 )
|
613
|
-
assert_not_nil start_status
|
614
|
-
child_pid = start_status[1].to_i
|
615
|
-
assert_operator child_pid, :>, 0
|
616
|
-
|
617
|
-
# send signal to abort the worker
|
618
|
-
Process.kill('TERM', worker_pid)
|
619
|
-
Process.waitpid(worker_pid)
|
620
|
-
|
621
|
-
# wait to see how it all came down
|
622
|
-
result = Resque.redis.blpop( 'sigterm-test:result', 5 )
|
623
|
-
assert_not_nil result
|
624
|
-
assert !result[1].start_with?('Finished Normally'), 'Job Finished normally. Sleep not long enough?'
|
625
|
-
assert result[1].start_with? 'Caught SignalException', 'Signal exception not raised in child.'
|
626
|
-
|
627
|
-
# ensure that the child pid is no longer running
|
628
|
-
child_still_running = !(`ps -p #{child_pid.to_s} -o pid=`).empty?
|
629
|
-
assert !child_still_running
|
630
|
-
|
631
|
-
# see if post-cleanup occurred. This should happen IFF the rescue_time is less than the term_timeout
|
632
|
-
post_cleanup_occurred = Resque.redis.lpop( 'sigterm-test:final' )
|
633
|
-
assert post_cleanup_occurred, 'post cleanup did not occur. SIGKILL sent too early?' if rescue_time.nil?
|
634
|
-
assert !post_cleanup_occurred, 'post cleanup occurred. SIGKILL sent too late?' unless rescue_time.nil?
|
635
|
-
|
636
|
-
ensure
|
637
|
-
remaining_keys = Resque.redis.keys('sigterm-test:*') || []
|
638
|
-
Resque.redis.del(*remaining_keys) unless remaining_keys.empty?
|
639
|
-
end
|
640
|
-
end
|
641
|
-
end
|
642
|
-
end
|
643
|
-
|
644
|
-
test "displays warning when not using term_child" do
|
645
|
-
stdout, stderr = capture_io { @worker.work(0) }
|
646
|
-
|
647
|
-
assert stderr.match(/^WARNING:/)
|
648
|
-
end
|
649
|
-
|
650
|
-
test "it does not display warning when using term_child" do
|
651
|
-
@worker.term_child = "1"
|
652
|
-
stdout, stderr = capture_io { @worker.work(0) }
|
653
|
-
|
654
|
-
assert !stderr.match(/^WARNING:/)
|
655
|
-
end
|
656
|
-
end
|
657
|
-
end
|