resque 1.23.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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