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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +271 -0
  3. data/README.markdown +454 -484
  4. data/Rakefile +4 -17
  5. data/bin/resque-web +10 -22
  6. data/lib/resque/data_store.rb +335 -0
  7. data/lib/resque/errors.rb +15 -1
  8. data/lib/resque/failure/airbrake.rb +32 -4
  9. data/lib/resque/failure/base.rb +16 -7
  10. data/lib/resque/failure/multiple.rb +26 -8
  11. data/lib/resque/failure/redis.rb +92 -15
  12. data/lib/resque/failure/redis_multi_queue.rb +104 -0
  13. data/lib/resque/failure.rb +62 -32
  14. data/lib/resque/helpers.rb +11 -57
  15. data/lib/resque/job.rb +79 -12
  16. data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
  17. data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
  18. data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
  19. data/lib/resque/logging.rb +18 -0
  20. data/lib/resque/plugin.rb +22 -10
  21. data/lib/resque/railtie.rb +10 -0
  22. data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
  23. data/lib/resque/server/public/jquery.relatize_date.js +4 -4
  24. data/lib/resque/server/public/main.js +3 -0
  25. data/lib/resque/server/public/ranger.js +16 -8
  26. data/lib/resque/server/public/style.css +13 -8
  27. data/lib/resque/server/views/error.erb +1 -1
  28. data/lib/resque/server/views/failed.erb +27 -59
  29. data/lib/resque/server/views/failed_job.erb +50 -0
  30. data/lib/resque/server/views/failed_queues_overview.erb +24 -0
  31. data/lib/resque/server/views/job_class.erb +8 -0
  32. data/lib/resque/server/views/key_sets.erb +2 -4
  33. data/lib/resque/server/views/key_string.erb +1 -1
  34. data/lib/resque/server/views/layout.erb +7 -6
  35. data/lib/resque/server/views/next_more.erb +22 -10
  36. data/lib/resque/server/views/processing.erb +2 -0
  37. data/lib/resque/server/views/queues.erb +22 -13
  38. data/lib/resque/server/views/stats.erb +5 -5
  39. data/lib/resque/server/views/workers.erb +4 -4
  40. data/lib/resque/server/views/working.erb +10 -11
  41. data/lib/resque/server.rb +51 -108
  42. data/lib/resque/server_helper.rb +185 -0
  43. data/lib/resque/stat.rb +19 -7
  44. data/lib/resque/tasks.rb +26 -25
  45. data/lib/resque/thread_signal.rb +24 -0
  46. data/lib/resque/vendor/utf8_util.rb +2 -8
  47. data/lib/resque/version.rb +1 -1
  48. data/lib/resque/web_runner.rb +374 -0
  49. data/lib/resque/worker.rb +487 -163
  50. data/lib/resque.rb +332 -52
  51. data/lib/tasks/redis.rake +11 -11
  52. metadata +169 -149
  53. data/lib/resque/failure/hoptoad.rb +0 -33
  54. data/lib/resque/failure/thoughtbot.rb +0 -33
  55. data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
  56. data/lib/resque/server/test_helper.rb +0 -19
  57. data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
  58. data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
  59. data/test/airbrake_test.rb +0 -27
  60. data/test/hoptoad_test.rb +0 -26
  61. data/test/job_hooks_test.rb +0 -464
  62. data/test/job_plugins_test.rb +0 -230
  63. data/test/plugin_test.rb +0 -116
  64. data/test/redis-test-cluster.conf +0 -115
  65. data/test/redis-test.conf +0 -115
  66. data/test/resque-web_test.rb +0 -59
  67. data/test/resque_failure_redis_test.rb +0 -19
  68. data/test/resque_test.rb +0 -278
  69. data/test/test_helper.rb +0 -178
  70. 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