tr_resque 1.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/HISTORY.md +354 -0
  2. data/LICENSE +20 -0
  3. data/README.markdown +908 -0
  4. data/Rakefile +70 -0
  5. data/bin/resque +81 -0
  6. data/bin/resque-web +27 -0
  7. data/lib/resque.rb +369 -0
  8. data/lib/resque/errors.rb +10 -0
  9. data/lib/resque/failure.rb +96 -0
  10. data/lib/resque/failure/airbrake.rb +17 -0
  11. data/lib/resque/failure/base.rb +64 -0
  12. data/lib/resque/failure/hoptoad.rb +33 -0
  13. data/lib/resque/failure/multiple.rb +54 -0
  14. data/lib/resque/failure/redis.rb +51 -0
  15. data/lib/resque/failure/thoughtbot.rb +33 -0
  16. data/lib/resque/helpers.rb +94 -0
  17. data/lib/resque/job.rb +227 -0
  18. data/lib/resque/plugin.rb +66 -0
  19. data/lib/resque/server.rb +248 -0
  20. data/lib/resque/server/public/favicon.ico +0 -0
  21. data/lib/resque/server/public/idle.png +0 -0
  22. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  23. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  24. data/lib/resque/server/public/poll.png +0 -0
  25. data/lib/resque/server/public/ranger.js +73 -0
  26. data/lib/resque/server/public/reset.css +44 -0
  27. data/lib/resque/server/public/style.css +86 -0
  28. data/lib/resque/server/public/working.png +0 -0
  29. data/lib/resque/server/test_helper.rb +19 -0
  30. data/lib/resque/server/views/error.erb +1 -0
  31. data/lib/resque/server/views/failed.erb +67 -0
  32. data/lib/resque/server/views/key_sets.erb +19 -0
  33. data/lib/resque/server/views/key_string.erb +11 -0
  34. data/lib/resque/server/views/layout.erb +44 -0
  35. data/lib/resque/server/views/next_more.erb +10 -0
  36. data/lib/resque/server/views/overview.erb +4 -0
  37. data/lib/resque/server/views/queues.erb +49 -0
  38. data/lib/resque/server/views/stats.erb +62 -0
  39. data/lib/resque/server/views/workers.erb +109 -0
  40. data/lib/resque/server/views/working.erb +72 -0
  41. data/lib/resque/stat.rb +53 -0
  42. data/lib/resque/tasks.rb +61 -0
  43. data/lib/resque/version.rb +3 -0
  44. data/lib/resque/worker.rb +546 -0
  45. data/lib/tasks/redis.rake +161 -0
  46. data/lib/tasks/resque.rake +2 -0
  47. data/test/airbrake_test.rb +27 -0
  48. data/test/hoptoad_test.rb +26 -0
  49. data/test/job_hooks_test.rb +423 -0
  50. data/test/job_plugins_test.rb +230 -0
  51. data/test/plugin_test.rb +116 -0
  52. data/test/redis-test-cluster.conf +115 -0
  53. data/test/redis-test.conf +115 -0
  54. data/test/resque-web_test.rb +59 -0
  55. data/test/resque_test.rb +278 -0
  56. data/test/test_helper.rb +160 -0
  57. data/test/worker_test.rb +434 -0
  58. metadata +186 -0
@@ -0,0 +1,161 @@
1
+ # Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master
2
+ require 'fileutils'
3
+ require 'open-uri'
4
+ require 'pathname'
5
+
6
+ class RedisRunner
7
+ def self.redis_dir
8
+ @redis_dir ||= if ENV['PREFIX']
9
+ Pathname.new(ENV['PREFIX'])
10
+ else
11
+ Pathname.new(`which redis-server`) + '..' + '..'
12
+ end
13
+ end
14
+
15
+ def self.bin_dir
16
+ redis_dir + 'bin'
17
+ end
18
+
19
+ def self.config
20
+ @config ||= if File.exists?(redis_dir + 'etc/redis.conf')
21
+ redis_dir + 'etc/redis.conf'
22
+ else
23
+ redis_dir + '../etc/redis.conf'
24
+ end
25
+ end
26
+
27
+ def self.dtach_socket
28
+ '/tmp/redis.dtach'
29
+ end
30
+
31
+ # Just check for existance of dtach socket
32
+ def self.running?
33
+ File.exists? dtach_socket
34
+ end
35
+
36
+ def self.start
37
+ puts 'Detach with Ctrl+\ Re-attach with rake redis:attach'
38
+ sleep 1
39
+ command = "#{bin_dir}/dtach -A #{dtach_socket} #{bin_dir}/redis-server #{config}"
40
+ sh command
41
+ end
42
+
43
+ def self.attach
44
+ exec "#{bin_dir}/dtach -a #{dtach_socket}"
45
+ end
46
+
47
+ def self.stop
48
+ sh 'echo "SHUTDOWN" | nc localhost 6379'
49
+ end
50
+ end
51
+
52
+ INSTALL_DIR = ENV['INSTALL_DIR'] || '/tmp/redis'
53
+
54
+ namespace :redis do
55
+ desc 'About redis'
56
+ task :about do
57
+ puts "\nSee http://code.google.com/p/redis/ for information about redis.\n\n"
58
+ end
59
+
60
+ desc 'Start redis'
61
+ task :start do
62
+ RedisRunner.start
63
+ end
64
+
65
+ desc 'Stop redis'
66
+ task :stop do
67
+ RedisRunner.stop
68
+ end
69
+
70
+ desc 'Restart redis'
71
+ task :restart do
72
+ RedisRunner.stop
73
+ RedisRunner.start
74
+ end
75
+
76
+ desc 'Attach to redis dtach socket'
77
+ task :attach do
78
+ RedisRunner.attach
79
+ end
80
+
81
+ desc <<-DOC
82
+ Install the latest verison of Redis from Github (requires git, duh).
83
+ Use INSTALL_DIR env var like "rake redis:install INSTALL_DIR=~/tmp"
84
+ in order to get an alternate location for your install files.
85
+ DOC
86
+
87
+ task :install => [:about, :download, :make] do
88
+ bin_dir = '/usr/bin'
89
+ conf_dir = '/etc'
90
+
91
+ if ENV['PREFIX']
92
+ bin_dir = "#{ENV['PREFIX']}/bin"
93
+ sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
94
+
95
+ conf_dir = "#{ENV['PREFIX']}/etc"
96
+ sh "mkdir -p #{conf_dir}" unless File.exists?("#{conf_dir}")
97
+ end
98
+
99
+ %w(redis-benchmark redis-cli redis-server).each do |bin|
100
+ sh "cp #{INSTALL_DIR}/src/#{bin} #{bin_dir}"
101
+ end
102
+
103
+ puts "Installed redis-benchmark, redis-cli and redis-server to #{bin_dir}"
104
+
105
+ unless File.exists?("#{conf_dir}/redis.conf")
106
+ sh "cp #{INSTALL_DIR}/redis.conf #{conf_dir}/redis.conf"
107
+ puts "Installed redis.conf to #{conf_dir} \n You should look at this file!"
108
+ end
109
+ end
110
+
111
+ task :make do
112
+ sh "cd #{INSTALL_DIR}/src && make clean"
113
+ sh "cd #{INSTALL_DIR}/src && make"
114
+ end
115
+
116
+ desc "Download package"
117
+ task :download do
118
+ sh "rm -rf #{INSTALL_DIR}/" if File.exists?("#{INSTALL_DIR}/.svn")
119
+ sh "git clone git://github.com/antirez/redis.git #{INSTALL_DIR}" unless File.exists?(INSTALL_DIR)
120
+ sh "cd #{INSTALL_DIR} && git pull" if File.exists?("#{INSTALL_DIR}/.git")
121
+ end
122
+ end
123
+
124
+ namespace :dtach do
125
+ desc 'About dtach'
126
+ task :about do
127
+ puts "\nSee http://dtach.sourceforge.net/ for information about dtach.\n\n"
128
+ end
129
+
130
+ desc 'Install dtach 0.8 from source'
131
+ task :install => [:about, :download, :make] do
132
+
133
+ bin_dir = "/usr/bin"
134
+
135
+
136
+ if ENV['PREFIX']
137
+ bin_dir = "#{ENV['PREFIX']}/bin"
138
+ sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
139
+ end
140
+
141
+ sh "cp #{INSTALL_DIR}/dtach-0.8/dtach #{bin_dir}"
142
+ end
143
+
144
+ task :make do
145
+ sh "cd #{INSTALL_DIR}/dtach-0.8/ && ./configure && make"
146
+ end
147
+
148
+ desc "Download package"
149
+ task :download do
150
+ unless File.exists?("#{INSTALL_DIR}/dtach-0.8.tar.gz")
151
+ require 'net/http'
152
+
153
+ url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
154
+ open("#{INSTALL_DIR}/dtach-0.8.tar.gz", 'wb') do |file| file.write(open(url).read) end
155
+ end
156
+
157
+ unless File.directory?("#{INSTALL_DIR}/dtach-0.8")
158
+ sh "cd #{INSTALL_DIR} && tar xzf dtach-0.8.tar.gz"
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'resque/tasks'
@@ -0,0 +1,27 @@
1
+
2
+ require 'test_helper'
3
+
4
+ begin
5
+ require 'airbrake'
6
+ rescue LoadError
7
+ warn "Install airbrake gem to run Airbrake tests."
8
+ end
9
+
10
+ if defined? Airbrake
11
+ require 'resque/failure/airbrake'
12
+ context "Airbrake" do
13
+ test "should be notified of an error" do
14
+ exception = StandardError.new("BOOM")
15
+ worker = Resque::Worker.new(:test)
16
+ queue = "test"
17
+ payload = {'class' => Object, 'args' => 66}
18
+
19
+ Airbrake.expects(:notify_or_ignore).with(
20
+ exception,
21
+ :parameters => {:payload_class => 'Object', :payload_args => '66'})
22
+
23
+ backend = Resque::Failure::Airbrake.new(exception, worker, queue, payload)
24
+ backend.save
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ begin
4
+ require 'hoptoad_notifier'
5
+ rescue LoadError
6
+ warn "Install hoptoad_notifier gem to run Hoptoad tests."
7
+ end
8
+
9
+ if defined? HoptoadNotifier
10
+ require 'resque/failure/hoptoad'
11
+ context "Hoptoad" do
12
+ test "should be notified of an error" do
13
+ exception = StandardError.new("BOOM")
14
+ worker = Resque::Worker.new(:test)
15
+ queue = "test"
16
+ payload = {'class' => Object, 'args' => 66}
17
+
18
+ HoptoadNotifier.expects(:notify_or_ignore).with(
19
+ exception,
20
+ :parameters => {:payload_class => 'Object', :payload_args => '66'})
21
+
22
+ backend = Resque::Failure::Hoptoad.new(exception, worker, queue, payload)
23
+ backend.save
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,423 @@
1
+ require 'test_helper'
2
+
3
+ context "Resque::Job before_perform" do
4
+ include PerformJob
5
+
6
+ class ::BeforePerformJob
7
+ def self.before_perform_record_history(history)
8
+ history << :before_perform
9
+ end
10
+
11
+ def self.perform(history)
12
+ history << :perform
13
+ end
14
+ end
15
+
16
+ test "it runs before_perform before perform" do
17
+ result = perform_job(BeforePerformJob, history=[])
18
+ assert_equal true, result, "perform returned true"
19
+ assert_equal history, [:before_perform, :perform]
20
+ end
21
+
22
+ class ::BeforePerformJobFails
23
+ def self.before_perform_fail_job(history)
24
+ history << :before_perform
25
+ raise StandardError
26
+ end
27
+ def self.perform(history)
28
+ history << :perform
29
+ end
30
+ end
31
+
32
+ test "raises an error and does not perform if before_perform fails" do
33
+ history = []
34
+ assert_raises StandardError do
35
+ perform_job(BeforePerformJobFails, history)
36
+ end
37
+ assert_equal history, [:before_perform], "Only before_perform was run"
38
+ end
39
+
40
+ class ::BeforePerformJobAborts
41
+ def self.before_perform_abort(history)
42
+ history << :before_perform
43
+ raise Resque::Job::DontPerform
44
+ end
45
+ def self.perform(history)
46
+ history << :perform
47
+ end
48
+ end
49
+
50
+ test "does not perform if before_perform raises Resque::Job::DontPerform" do
51
+ result = perform_job(BeforePerformJobAborts, history=[])
52
+ assert_equal false, result, "perform returned false"
53
+ assert_equal history, [:before_perform], "Only before_perform was run"
54
+ end
55
+ end
56
+
57
+ context "Resque::Job after_perform" do
58
+ include PerformJob
59
+
60
+ class ::AfterPerformJob
61
+ def self.perform(history)
62
+ history << :perform
63
+ end
64
+ def self.after_perform_record_history(history)
65
+ history << :after_perform
66
+ end
67
+ end
68
+
69
+ test "it runs after_perform after perform" do
70
+ result = perform_job(AfterPerformJob, history=[])
71
+ assert_equal true, result, "perform returned true"
72
+ assert_equal history, [:perform, :after_perform]
73
+ end
74
+
75
+ class ::AfterPerformJobFails
76
+ def self.perform(history)
77
+ history << :perform
78
+ end
79
+ def self.after_perform_fail_job(history)
80
+ history << :after_perform
81
+ raise StandardError
82
+ end
83
+ end
84
+
85
+ test "raises an error but has already performed if after_perform fails" do
86
+ history = []
87
+ assert_raises StandardError do
88
+ perform_job(AfterPerformJobFails, history)
89
+ end
90
+ assert_equal history, [:perform, :after_perform], "Only after_perform was run"
91
+ end
92
+ end
93
+
94
+ context "Resque::Job around_perform" do
95
+ include PerformJob
96
+
97
+ class ::AroundPerformJob
98
+ def self.perform(history)
99
+ history << :perform
100
+ end
101
+ def self.around_perform_record_history(history)
102
+ history << :start_around_perform
103
+ yield
104
+ history << :finish_around_perform
105
+ end
106
+ end
107
+
108
+ test "it runs around_perform then yields in order to perform" do
109
+ result = perform_job(AroundPerformJob, history=[])
110
+ assert_equal true, result, "perform returned true"
111
+ assert_equal history, [:start_around_perform, :perform, :finish_around_perform]
112
+ end
113
+
114
+ class ::AroundPerformJobFailsBeforePerforming
115
+ def self.perform(history)
116
+ history << :perform
117
+ end
118
+ def self.around_perform_fail(history)
119
+ history << :start_around_perform
120
+ raise StandardError
121
+ yield
122
+ history << :finish_around_perform
123
+ end
124
+ end
125
+
126
+ test "raises an error and does not perform if around_perform fails before yielding" do
127
+ history = []
128
+ assert_raises StandardError do
129
+ perform_job(AroundPerformJobFailsBeforePerforming, history)
130
+ end
131
+ assert_equal history, [:start_around_perform], "Only part of around_perform was run"
132
+ end
133
+
134
+ class ::AroundPerformJobFailsWhilePerforming
135
+ def self.perform(history)
136
+ history << :perform
137
+ raise StandardError
138
+ end
139
+ def self.around_perform_fail_in_yield(history)
140
+ history << :start_around_perform
141
+ begin
142
+ yield
143
+ ensure
144
+ history << :ensure_around_perform
145
+ end
146
+ history << :finish_around_perform
147
+ end
148
+ end
149
+
150
+ test "raises an error but may handle exceptions if perform fails" do
151
+ history = []
152
+ assert_raises StandardError do
153
+ perform_job(AroundPerformJobFailsWhilePerforming, history)
154
+ end
155
+ assert_equal history, [:start_around_perform, :perform, :ensure_around_perform], "Only part of around_perform was run"
156
+ end
157
+
158
+ class ::AroundPerformJobDoesNotHaveToYield
159
+ def self.perform(history)
160
+ history << :perform
161
+ end
162
+ def self.around_perform_dont_yield(history)
163
+ history << :start_around_perform
164
+ history << :finish_around_perform
165
+ end
166
+ end
167
+
168
+ test "around_perform is not required to yield" do
169
+ history = []
170
+ result = perform_job(AroundPerformJobDoesNotHaveToYield, history)
171
+ assert_equal false, result, "perform returns false"
172
+ assert_equal history, [:start_around_perform, :finish_around_perform], "perform was not run"
173
+ end
174
+ end
175
+
176
+ context "Resque::Job on_failure" do
177
+ include PerformJob
178
+
179
+ class ::FailureJobThatDoesNotFail
180
+ def self.perform(history)
181
+ history << :perform
182
+ end
183
+ def self.on_failure_record_failure(exception, history)
184
+ history << exception.message
185
+ end
186
+ end
187
+
188
+ test "it does not call on_failure if no failures occur" do
189
+ result = perform_job(FailureJobThatDoesNotFail, history=[])
190
+ assert_equal true, result, "perform returned true"
191
+ assert_equal history, [:perform]
192
+ end
193
+
194
+ class ::FailureJobThatFails
195
+ def self.perform(history)
196
+ history << :perform
197
+ raise StandardError, "oh no"
198
+ end
199
+ def self.on_failure_record_failure(exception, history)
200
+ history << exception.message
201
+ end
202
+ end
203
+
204
+ test "it calls on_failure with the exception and then re-raises the exception" do
205
+ history = []
206
+ assert_raises StandardError do
207
+ perform_job(FailureJobThatFails, history)
208
+ end
209
+ assert_equal history, [:perform, "oh no"]
210
+ end
211
+
212
+ class ::FailureJobThatFailsBadly
213
+ def self.perform(history)
214
+ history << :perform
215
+ raise SyntaxError, "oh no"
216
+ end
217
+ def self.on_failure_record_failure(exception, history)
218
+ history << exception.message
219
+ end
220
+ end
221
+
222
+ test "it calls on_failure even with bad exceptions" do
223
+ history = []
224
+ assert_raises SyntaxError do
225
+ perform_job(FailureJobThatFailsBadly, history)
226
+ end
227
+ assert_equal history, [:perform, "oh no"]
228
+ end
229
+ end
230
+
231
+ context "Resque::Job after_enqueue" do
232
+ include PerformJob
233
+
234
+ class ::AfterEnqueueJob
235
+ @queue = :jobs
236
+ def self.after_enqueue_record_history(history)
237
+ history << :after_enqueue
238
+ end
239
+
240
+ def self.perform(history)
241
+ end
242
+ end
243
+
244
+ test "the after enqueue hook should run" do
245
+ history = []
246
+ @worker = Resque::Worker.new(:jobs)
247
+ Resque.enqueue(AfterEnqueueJob, history)
248
+ @worker.work(0)
249
+ assert_equal history, [:after_enqueue], "after_enqueue was not run"
250
+ end
251
+ end
252
+
253
+
254
+ context "Resque::Job before_enqueue" do
255
+ include PerformJob
256
+
257
+ class ::BeforeEnqueueJob
258
+ @queue = :jobs
259
+ def self.before_enqueue_record_history(history)
260
+ history << :before_enqueue
261
+ end
262
+
263
+ def self.perform(history)
264
+ end
265
+ end
266
+
267
+ class ::BeforeEnqueueJobAbort
268
+ @queue = :jobs
269
+ def self.before_enqueue_abort(history)
270
+ false
271
+ end
272
+
273
+ def self.perform(history)
274
+ end
275
+ end
276
+
277
+ test "the before enqueue hook should run" do
278
+ history = []
279
+ @worker = Resque::Worker.new(:jobs)
280
+ assert Resque.enqueue(BeforeEnqueueJob, history)
281
+ @worker.work(0)
282
+ assert_equal history, [:before_enqueue], "before_enqueue was not run"
283
+ end
284
+
285
+ test "a before enqueue hook that returns false should prevent the job from getting queued" do
286
+ history = []
287
+ @worker = Resque::Worker.new(:jobs)
288
+ assert_nil Resque.enqueue(BeforeEnqueueJobAbort, history)
289
+ assert_equal 0, Resque.size(:jobs)
290
+ end
291
+ end
292
+
293
+ context "Resque::Job after_dequeue" do
294
+ include PerformJob
295
+
296
+ class ::AfterDequeueJob
297
+ @queue = :jobs
298
+ def self.after_dequeue_record_history(history)
299
+ history << :after_dequeue
300
+ end
301
+
302
+ def self.perform(history)
303
+ end
304
+ end
305
+
306
+ test "the after dequeue hook should run" do
307
+ history = []
308
+ @worker = Resque::Worker.new(:jobs)
309
+ Resque.dequeue(AfterDequeueJob, history)
310
+ @worker.work(0)
311
+ assert_equal history, [:after_dequeue], "after_dequeue was not run"
312
+ end
313
+ end
314
+
315
+
316
+ context "Resque::Job before_dequeue" do
317
+ include PerformJob
318
+
319
+ class ::BeforeDequeueJob
320
+ @queue = :jobs
321
+ def self.before_dequeue_record_history(history)
322
+ history << :before_dequeue
323
+ end
324
+
325
+ def self.perform(history)
326
+ end
327
+ end
328
+
329
+ class ::BeforeDequeueJobAbort
330
+ @queue = :jobs
331
+ def self.before_dequeue_abort(history)
332
+ false
333
+ end
334
+
335
+ def self.perform(history)
336
+ end
337
+ end
338
+
339
+ test "the before dequeue hook should run" do
340
+ history = []
341
+ @worker = Resque::Worker.new(:jobs)
342
+ Resque.dequeue(BeforeDequeueJob, history)
343
+ @worker.work(0)
344
+ assert_equal history, [:before_dequeue], "before_dequeue was not run"
345
+ end
346
+
347
+ test "a before dequeue hook that returns false should prevent the job from getting dequeued" do
348
+ history = []
349
+ assert_equal nil, Resque.dequeue(BeforeDequeueJobAbort, history)
350
+ end
351
+ end
352
+
353
+ context "Resque::Job all hooks" do
354
+ include PerformJob
355
+
356
+ class ::VeryHookyJob
357
+ def self.before_perform_record_history(history)
358
+ history << :before_perform
359
+ end
360
+ def self.around_perform_record_history(history)
361
+ history << :start_around_perform
362
+ yield
363
+ history << :finish_around_perform
364
+ end
365
+ def self.perform(history)
366
+ history << :perform
367
+ end
368
+ def self.after_perform_record_history(history)
369
+ history << :after_perform
370
+ end
371
+ def self.on_failure_record_history(exception, history)
372
+ history << exception.message
373
+ end
374
+ end
375
+
376
+ test "the complete hook order" do
377
+ result = perform_job(VeryHookyJob, history=[])
378
+ assert_equal true, result, "perform returned true"
379
+ assert_equal history, [
380
+ :before_perform,
381
+ :start_around_perform,
382
+ :perform,
383
+ :finish_around_perform,
384
+ :after_perform
385
+ ]
386
+ end
387
+
388
+ class ::VeryHookyJobThatFails
389
+ def self.before_perform_record_history(history)
390
+ history << :before_perform
391
+ end
392
+ def self.around_perform_record_history(history)
393
+ history << :start_around_perform
394
+ yield
395
+ history << :finish_around_perform
396
+ end
397
+ def self.perform(history)
398
+ history << :perform
399
+ end
400
+ def self.after_perform_record_history(history)
401
+ history << :after_perform
402
+ raise StandardError, "oh no"
403
+ end
404
+ def self.on_failure_record_history(exception, history)
405
+ history << exception.message
406
+ end
407
+ end
408
+
409
+ test "the complete hook order with a failure at the last minute" do
410
+ history = []
411
+ assert_raises StandardError do
412
+ perform_job(VeryHookyJobThatFails, history)
413
+ end
414
+ assert_equal history, [
415
+ :before_perform,
416
+ :start_around_perform,
417
+ :perform,
418
+ :finish_around_perform,
419
+ :after_perform,
420
+ "oh no"
421
+ ]
422
+ end
423
+ end