nfo-resque-mongo 1.15.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 (55) hide show
  1. data/HISTORY.md +259 -0
  2. data/LICENSE +20 -0
  3. data/README.markdown +828 -0
  4. data/Rakefile +73 -0
  5. data/bin/resque +75 -0
  6. data/bin/resque-web +23 -0
  7. data/lib/resque/errors.rb +10 -0
  8. data/lib/resque/failure/base.rb +74 -0
  9. data/lib/resque/failure/hoptoad.rb +139 -0
  10. data/lib/resque/failure/mongo.rb +92 -0
  11. data/lib/resque/failure/multiple.rb +60 -0
  12. data/lib/resque/failure.rb +82 -0
  13. data/lib/resque/helpers.rb +79 -0
  14. data/lib/resque/job.rb +228 -0
  15. data/lib/resque/plugin.rb +51 -0
  16. data/lib/resque/queue_stats.rb +58 -0
  17. data/lib/resque/server/public/idle.png +0 -0
  18. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  19. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  20. data/lib/resque/server/public/poll.png +0 -0
  21. data/lib/resque/server/public/ranger.js +73 -0
  22. data/lib/resque/server/public/reset.css +48 -0
  23. data/lib/resque/server/public/style.css +86 -0
  24. data/lib/resque/server/public/working.png +0 -0
  25. data/lib/resque/server/test_helper.rb +19 -0
  26. data/lib/resque/server/views/error.erb +1 -0
  27. data/lib/resque/server/views/failed.erb +75 -0
  28. data/lib/resque/server/views/key_sets.erb +19 -0
  29. data/lib/resque/server/views/key_string.erb +11 -0
  30. data/lib/resque/server/views/layout.erb +38 -0
  31. data/lib/resque/server/views/next_more.erb +19 -0
  32. data/lib/resque/server/views/overview.erb +4 -0
  33. data/lib/resque/server/views/queues.erb +49 -0
  34. data/lib/resque/server/views/stats.erb +62 -0
  35. data/lib/resque/server/views/workers.erb +109 -0
  36. data/lib/resque/server/views/working.erb +68 -0
  37. data/lib/resque/server.rb +222 -0
  38. data/lib/resque/stat.rb +55 -0
  39. data/lib/resque/tasks.rb +42 -0
  40. data/lib/resque/version.rb +3 -0
  41. data/lib/resque/worker.rb +524 -0
  42. data/lib/resque.rb +384 -0
  43. data/tasks/redis.rake +161 -0
  44. data/tasks/resque.rake +2 -0
  45. data/test/dump.rdb +0 -0
  46. data/test/job_hooks_test.rb +323 -0
  47. data/test/job_plugins_test.rb +230 -0
  48. data/test/plugin_test.rb +116 -0
  49. data/test/queue_stats_test.rb +57 -0
  50. data/test/redis-test.conf +115 -0
  51. data/test/resque-web_test.rb +48 -0
  52. data/test/resque_test.rb +256 -0
  53. data/test/test_helper.rb +151 -0
  54. data/test/worker_test.rb +356 -0
  55. metadata +166 -0
@@ -0,0 +1,151 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+ $TESTING = true
4
+ require 'test/unit'
5
+ require 'rubygems'
6
+ require 'resque'
7
+
8
+ begin
9
+ require 'leftright'
10
+ rescue LoadError
11
+ end
12
+
13
+
14
+ #
15
+ # make sure we can run redis
16
+ #
17
+
18
+ # if !system("which redis-server")
19
+ # puts '', "** can't find `redis-server` in your path"
20
+ # puts "** try running `sudo rake install`"
21
+ # abort ''
22
+ # end
23
+
24
+
25
+ #
26
+ # start our own redis when the tests start,
27
+ # kill it when they end
28
+ #
29
+
30
+ at_exit do
31
+ next if $!
32
+
33
+ if defined?(MiniTest)
34
+ exit_code = MiniTest::Unit.new.run(ARGV)
35
+ else
36
+ exit_code = Test::Unit::AutoRunner.run
37
+ end
38
+ end
39
+
40
+ Resque.mongo = 'localhost:27017'
41
+
42
+ module Resque
43
+ # Drop all collections in the 'monque' database.
44
+ # Note: do not drop the database directly, as mongod allocates disk space
45
+ # each time it's re-created.
46
+ def flushall
47
+ for name in @db.collection_names
48
+ begin
49
+ @db.drop_collection(name)
50
+ rescue Mongo::OperationFailure
51
+ # "can't drop system ns"
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ ##
58
+ # test/spec/mini 3
59
+ # http://gist.github.com/25455
60
+ # chris@ozmm.org
61
+ #
62
+ def context(*args, &block)
63
+ return super unless (name = args.first) && block
64
+ require 'test/unit'
65
+ klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
66
+ def self.test(name, &block)
67
+ define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
68
+ end
69
+ def self.xtest(*args) end
70
+ def self.setup(&block) define_method(:setup, &block) end
71
+ def self.teardown(&block) define_method(:teardown, &block) end
72
+ end
73
+ (class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
74
+ klass.class_eval &block
75
+ # XXX: In 1.8.x, not all tests will run unless anonymous classes are kept in scope.
76
+ ($test_classes ||= []) << klass
77
+ end
78
+
79
+ ##
80
+ # Helper to perform job classes
81
+ #
82
+ module PerformJob
83
+ def perform_job(klass, *args)
84
+ resque_job = Resque::Job.new(:testqueue, 'class' => klass, 'args' => args)
85
+ resque_job.perform
86
+ end
87
+ end
88
+
89
+ #
90
+ # fixture classes
91
+ #
92
+
93
+ class SomeJob
94
+ def self.perform(repo_id, path)
95
+ end
96
+ end
97
+
98
+ class SomeIvarJob < SomeJob
99
+ @queue = :ivar
100
+ end
101
+
102
+ class SomeMethodJob < SomeJob
103
+ def self.queue
104
+ :method
105
+ end
106
+ end
107
+
108
+ class BadJob
109
+ def self.perform
110
+ raise "Bad job!"
111
+ end
112
+ end
113
+
114
+ class GoodJob
115
+ def self.perform(name)
116
+ "Good job, #{name}"
117
+ end
118
+ end
119
+
120
+ class BadJobWithSyntaxError
121
+ def self.perform
122
+ raise SyntaxError, "Extra Bad job!"
123
+ end
124
+ end
125
+
126
+ class BadFailureBackend < Resque::Failure::Base
127
+ def save
128
+ raise Exception.new("Failure backend error")
129
+ end
130
+ end
131
+
132
+ def with_failure_backend(failure_backend, &block)
133
+ previous_backend = Resque::Failure.backend
134
+ Resque::Failure.backend = failure_backend
135
+ yield block
136
+ ensure
137
+ Resque::Failure.backend = previous_backend
138
+ end
139
+
140
+ class Time
141
+ # Thanks, Timecop
142
+ class << self
143
+ alias_method :now_without_mock_time, :now
144
+
145
+ def now_with_mock_time
146
+ $fake_time || now_without_mock_time
147
+ end
148
+
149
+ alias_method :now, :now_with_mock_time
150
+ end
151
+ end
@@ -0,0 +1,356 @@
1
+ require 'test_helper'
2
+
3
+ context "Resque::Worker" do
4
+ setup do
5
+ Resque.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 on exit" do
36
+ job = Resque::Job.new(:jobs, [GoodJob, "blah"])
37
+ @worker.working_on(job)
38
+ @worker.unregister_worker
39
+ assert_equal 1, Resque::Failure.count
40
+ end
41
+
42
+ test "can peek at failed jobs" do
43
+ 10.times { Resque::Job.create(:jobs, BadJob) }
44
+ @worker.work(0)
45
+
46
+ assert_equal 10, Resque::Failure.count
47
+ assert_equal 10, Resque::Failure.all(0, 20).size
48
+ end
49
+
50
+ test "can clear failed jobs" do
51
+ Resque::Job.create(:jobs, BadJob)
52
+ @worker.work(0)
53
+ assert_equal 1, Resque::Failure.count
54
+ Resque::Failure.clear
55
+ assert_equal 0, Resque::Failure.count
56
+ end
57
+
58
+ test "catches exceptional jobs" do
59
+ Resque::Job.create(:jobs, BadJob)
60
+ Resque::Job.create(:jobs, BadJob)
61
+ @worker.process
62
+ @worker.process
63
+ @worker.process
64
+ assert_equal 2, Resque::Failure.count
65
+ end
66
+
67
+ test "strips whitespace from queue names" do
68
+ queues = "critical, high, low".split(',')
69
+ worker = Resque::Worker.new(*queues)
70
+ assert_equal %w( critical high low ), worker.instance_variable_get('@queues')
71
+ end
72
+
73
+ test "can work on multiple queues" do
74
+ Resque::Job.create(:high, GoodJob)
75
+ Resque::Job.create(:critical, GoodJob)
76
+
77
+ worker = Resque::Worker.new(:critical, :high)
78
+
79
+ worker.process
80
+ assert_equal 1, Resque.size(:high)
81
+ assert_equal 0, Resque.size(:critical)
82
+
83
+ worker.process
84
+ assert_equal 0, Resque.size(:high)
85
+ end
86
+
87
+ test "can work on multiple queues with prefixes" do
88
+ Resque::Job.create(:high, GoodJob)
89
+ Resque::Job.create(:critically_high, GoodJob)
90
+ Resque::Job.create(:critical, GoodJob)
91
+
92
+ worker = Resque::Worker.new("critical*", :high)
93
+
94
+ worker.process
95
+ assert_equal 1, Resque.size(:high)
96
+ assert_equal 1, Resque.size(:critically_high)
97
+ assert_equal 0, Resque.size(:critical)
98
+
99
+ worker.process
100
+ assert_equal 1, Resque.size(:high)
101
+ assert_equal 0, Resque.size(:critically_high)
102
+ assert_equal 0, Resque.size(:critical)
103
+
104
+ worker.process
105
+ assert_equal 0, Resque.size(:high)
106
+ assert_equal 0, Resque.size(:critically_high)
107
+ assert_equal 0, Resque.size(:critical)
108
+ end
109
+
110
+ test "can work on all queues" do
111
+ Resque::Job.create(:high, GoodJob)
112
+ Resque::Job.create(:critical, GoodJob)
113
+ Resque::Job.create(:blahblah, GoodJob)
114
+
115
+ worker = Resque::Worker.new("*")
116
+
117
+ worker.work(0)
118
+ assert_equal 0, Resque.size(:high)
119
+ assert_equal 0, Resque.size(:critical)
120
+ assert_equal 0, Resque.size(:blahblah)
121
+ end
122
+
123
+ test "processes * queues in alphabetical order" do
124
+ Resque::Job.create(:high, GoodJob)
125
+ Resque::Job.create(:critical, GoodJob)
126
+ Resque::Job.create(:blahblah, GoodJob)
127
+
128
+ worker = Resque::Worker.new("*")
129
+ processed_queues = []
130
+
131
+ worker.work(0) do |job|
132
+ processed_queues << job.queue
133
+ end
134
+
135
+ assert_equal %w( jobs high critical blahblah ).sort, processed_queues
136
+ end
137
+
138
+ test "has a unique id" do
139
+ assert_equal "#{`hostname`.chomp}:#{$$}:jobs", @worker.to_s
140
+ end
141
+
142
+ test "complains if no queues are given" do
143
+ assert_raise Resque::NoQueueError do
144
+ Resque::Worker.new
145
+ end
146
+ end
147
+
148
+ test "fails if a job class has no `perform` method" do
149
+ worker = Resque::Worker.new(:perform_less)
150
+ Resque::Job.create(:perform_less, Object)
151
+
152
+ assert_equal 0, Resque::Failure.count
153
+ worker.work(0)
154
+ assert_equal 1, Resque::Failure.count
155
+ end
156
+
157
+ test "inserts itself into the 'workers' list on startup" do
158
+ @worker.work(0) do
159
+ assert_equal @worker, Resque.workers[0]
160
+ end
161
+ end
162
+
163
+ test "removes itself from the 'workers' list on shutdown" do
164
+ @worker.work(0) do
165
+ assert_equal @worker, Resque.workers[0]
166
+ end
167
+
168
+ assert_equal [], Resque.workers
169
+ end
170
+
171
+ test "removes worker with stringified id" do
172
+ @worker.work(0) do
173
+ worker_id = Resque.workers[0].to_s
174
+ Resque.remove_worker(worker_id)
175
+ assert_equal [], Resque.workers
176
+ end
177
+ end
178
+
179
+ test "records what it is working on" do
180
+ @worker.work(0) do
181
+ task = @worker.job
182
+ assert task
183
+ assert_equal({"args"=>[20, "/tmp"], "class"=>"SomeJob"}, task['payload'])
184
+ assert task['run_at']
185
+ assert_equal 'jobs', task['queue']
186
+ end
187
+ end
188
+
189
+ test "clears its status when not working on anything" do
190
+ @worker.work(0)
191
+ assert_equal Hash.new, @worker.job
192
+ end
193
+
194
+ test "knows when it is working" do
195
+ @worker.work(0) do
196
+ assert @worker.working?
197
+ end
198
+ end
199
+
200
+ test "knows when it is idle" do
201
+ @worker.work(0)
202
+ assert @worker.idle?
203
+ end
204
+
205
+ test "knows who is working" do
206
+ @worker.work(0) do
207
+ assert_equal [@worker], Resque.working
208
+ end
209
+ end
210
+
211
+ test "keeps track of how many jobs it has processed" do
212
+ Resque::Job.create(:jobs, BadJob)
213
+ Resque::Job.create(:jobs, BadJob)
214
+
215
+ 3.times do
216
+ job = @worker.reserve
217
+ @worker.process job
218
+ end
219
+ assert_equal 3, @worker.processed
220
+ end
221
+
222
+ test "keeps track of how many failures it has seen" do
223
+ Resque::Job.create(:jobs, BadJob)
224
+ Resque::Job.create(:jobs, BadJob)
225
+
226
+ 3.times do
227
+ job = @worker.reserve
228
+ @worker.process job
229
+ end
230
+ assert_equal 2, @worker.failed
231
+ end
232
+
233
+ test "stats are erased when the worker goes away" do
234
+ @worker.work(0)
235
+ assert_equal 0, @worker.processed
236
+ assert_equal 0, @worker.failed
237
+ end
238
+
239
+ test "knows when it started" do
240
+ time = Time.now
241
+ @worker.work(0) do
242
+ assert_equal time.to_i/1000, @worker.started.to_i/1000
243
+ end
244
+ end
245
+
246
+ test "knows whether it exists or not" do
247
+ @worker.work(0) do
248
+ assert Resque::Worker.exists?(@worker)
249
+ assert !Resque::Worker.exists?('blah-blah')
250
+ end
251
+ end
252
+
253
+ test "sets $0 while working" do
254
+ @worker.work(0) do
255
+ ver = Resque::Version
256
+ assert_match /resque-#{ver}: Processing jobs since/, $0
257
+ end
258
+ end
259
+
260
+ test "can be found" do
261
+ @worker.work(0) do
262
+ found = Resque::Worker.find(@worker.to_s)
263
+ assert_equal @worker.to_s, found.to_s
264
+ assert found.working?
265
+ assert_equal @worker.job, found.job
266
+ end
267
+ end
268
+
269
+ test "doesn't find fakes" do
270
+ @worker.work(0) do
271
+ found = Resque::Worker.find('blah-blah')
272
+ assert_equal nil, found
273
+ end
274
+ end
275
+
276
+ test "cleans up dead worker info on start (crash recovery)" do
277
+ # first we fake out two dead workers
278
+ workerA = Resque::Worker.new(:jobs)
279
+ workerA.instance_variable_set(:@to_s, "#{`hostname`.chomp}:1:jobs")
280
+ workerA.register_worker
281
+
282
+ workerB = Resque::Worker.new(:high, :low)
283
+ workerB.instance_variable_set(:@to_s, "#{`hostname`.chomp}:2:high,low")
284
+ workerB.register_worker
285
+
286
+ assert_equal 2, Resque.workers.size
287
+
288
+ # then we prune them
289
+ @worker.work(0) do
290
+ assert_equal 1, Resque.workers.size
291
+ end
292
+ end
293
+
294
+ test "Processed jobs count" do
295
+ @worker.work(0)
296
+ assert_equal 1, Resque.info[:processed]
297
+ end
298
+
299
+ test "Will call a before_first_fork hook only once" do
300
+ Resque.flushall
301
+ $BEFORE_FORK_CALLED = 0
302
+ Resque.before_first_fork = Proc.new { $BEFORE_FORK_CALLED += 1 }
303
+ workerA = Resque::Worker.new(:jobs)
304
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
305
+
306
+ assert_equal 0, $BEFORE_FORK_CALLED
307
+
308
+ workerA.work(0)
309
+ assert_equal 1, $BEFORE_FORK_CALLED
310
+
311
+ # TODO: Verify it's only run once. Not easy.
312
+ # workerA.work(0)
313
+ # assert_equal 1, $BEFORE_FORK_CALLED
314
+ end
315
+
316
+ test "Will call a before_fork hook before forking" do
317
+ Resque.flushall
318
+ $BEFORE_FORK_CALLED = false
319
+ Resque.before_fork = Proc.new { $BEFORE_FORK_CALLED = true }
320
+ workerA = Resque::Worker.new(:jobs)
321
+
322
+ assert !$BEFORE_FORK_CALLED
323
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
324
+ workerA.work(0)
325
+ assert $BEFORE_FORK_CALLED
326
+ end
327
+
328
+ test "very verbose works in the afternoon" do
329
+ require 'time'
330
+ $last_puts = ""
331
+ $fake_time = Time.parse("15:44:33 2011-03-02")
332
+ singleton = class << @worker; self end
333
+ singleton.send :define_method, :puts, lambda { |thing| $last_puts = thing }
334
+
335
+ @worker.very_verbose = true
336
+ @worker.log("some log text")
337
+
338
+ assert_match /\*\* \[15:44:33 2011-03-02\] \d+: some log text/, $last_puts
339
+ end
340
+
341
+ test "Will call an after_fork hook after forking" do
342
+ Resque.flushall
343
+ $AFTER_FORK_CALLED = false
344
+ Resque.after_fork = Proc.new { $AFTER_FORK_CALLED = true }
345
+ workerA = Resque::Worker.new(:jobs)
346
+
347
+ assert !$AFTER_FORK_CALLED
348
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
349
+ workerA.work(0)
350
+ assert $AFTER_FORK_CALLED
351
+ end
352
+
353
+ test "returns PID of running process" do
354
+ assert_equal @worker.to_s.split(":")[1].to_i, @worker.pid
355
+ end
356
+ end