resque-igo 1.1

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 (50) hide show
  1. data/HISTORY.md +225 -0
  2. data/LICENSE +20 -0
  3. data/README.markdown +855 -0
  4. data/Rakefile +70 -0
  5. data/bin/resque +57 -0
  6. data/bin/resque-web +23 -0
  7. data/lib/resque.rb +380 -0
  8. data/lib/resque/errors.rb +10 -0
  9. data/lib/resque/failure.rb +66 -0
  10. data/lib/resque/failure/base.rb +61 -0
  11. data/lib/resque/failure/hoptoad.rb +132 -0
  12. data/lib/resque/failure/multiple.rb +50 -0
  13. data/lib/resque/failure/redis.rb +40 -0
  14. data/lib/resque/helpers.rb +71 -0
  15. data/lib/resque/job.rb +209 -0
  16. data/lib/resque/plugin.rb +51 -0
  17. data/lib/resque/server.rb +247 -0
  18. data/lib/resque/server/public/idle.png +0 -0
  19. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  20. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  21. data/lib/resque/server/public/poll.png +0 -0
  22. data/lib/resque/server/public/ranger.js +67 -0
  23. data/lib/resque/server/public/reset.css +48 -0
  24. data/lib/resque/server/public/style.css +86 -0
  25. data/lib/resque/server/public/working.png +0 -0
  26. data/lib/resque/server/test_helper.rb +19 -0
  27. data/lib/resque/server/views/error.erb +1 -0
  28. data/lib/resque/server/views/failed.erb +53 -0
  29. data/lib/resque/server/views/key_sets.erb +20 -0
  30. data/lib/resque/server/views/key_string.erb +11 -0
  31. data/lib/resque/server/views/layout.erb +42 -0
  32. data/lib/resque/server/views/next_more.erb +10 -0
  33. data/lib/resque/server/views/overview.erb +4 -0
  34. data/lib/resque/server/views/queues.erb +65 -0
  35. data/lib/resque/server/views/stats.erb +73 -0
  36. data/lib/resque/server/views/workers.erb +109 -0
  37. data/lib/resque/server/views/working.erb +68 -0
  38. data/lib/resque/stat.rb +54 -0
  39. data/lib/resque/tasks.rb +39 -0
  40. data/lib/resque/version.rb +3 -0
  41. data/lib/resque/worker.rb +478 -0
  42. data/tasks/resque.rake +2 -0
  43. data/test/job_hooks_test.rb +323 -0
  44. data/test/job_plugins_test.rb +230 -0
  45. data/test/plugin_test.rb +116 -0
  46. data/test/resque-web_test.rb +54 -0
  47. data/test/resque_test.rb +351 -0
  48. data/test/test_helper.rb +166 -0
  49. data/test/worker_test.rb +302 -0
  50. metadata +180 -0
@@ -0,0 +1,166 @@
1
+ # -*- coding: utf-8 -*-
2
+ dir = File.dirname(File.expand_path(__FILE__))
3
+ $LOAD_PATH.unshift dir + '/../lib'
4
+ $TESTING = true
5
+ require 'test/unit'
6
+ require 'rubygems'
7
+ require 'resque'
8
+
9
+ begin
10
+ require 'leftright'
11
+ rescue LoadError
12
+ end
13
+
14
+ #
15
+ # start our own redis when the tests start,
16
+ # kill it when they end
17
+ #
18
+
19
+ ##
20
+ # test/spec/mini 3
21
+ # http://gist.github.com/25455
22
+ # chris@ozmm.org
23
+ #
24
+ def context(*args, &block)
25
+ return super unless (name = args.first) && block
26
+ require 'test/unit'
27
+ klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
28
+ def self.test(name, &block)
29
+ define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
30
+ end
31
+ def self.xtest(*args) end
32
+ def self.setup(&block) define_method(:setup, &block) end
33
+ def self.teardown(&block) define_method(:teardown, &block) end
34
+ end
35
+ (class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
36
+ klass.class_eval &block
37
+ end
38
+
39
+ ##
40
+ # Helper to perform job classes
41
+ #
42
+ module PerformJob
43
+ def perform_job(klass, *args)
44
+ resque_job = Resque::Job.new(:testqueue, 'class' => klass, 'args' => args)
45
+ resque_job.perform
46
+ end
47
+ end
48
+
49
+ #
50
+ # fixture classes
51
+ #
52
+
53
+ class SomeJob
54
+ def self.perform(repo_id, path)
55
+ end
56
+ end
57
+
58
+ class SomeIvarJob < SomeJob
59
+ @queue = :ivar
60
+ end
61
+
62
+ class SomeMethodJob < SomeJob
63
+ def self.queue
64
+ :method
65
+ end
66
+ end
67
+
68
+ class BadJob
69
+ def self.perform
70
+ raise "Bad job!"
71
+ end
72
+ end
73
+
74
+ class GoodJob
75
+ def self.perform(name)
76
+ "Good job, #{name}"
77
+ end
78
+ end
79
+
80
+ class BadJobWithSyntaxError
81
+ def self.perform
82
+ raise SyntaxError, "Extra Bad job!"
83
+ end
84
+ end
85
+
86
+ class UniqueJob
87
+ @queue = :unique
88
+ @unique_jobs = true
89
+ end
90
+
91
+ class NonUnique
92
+ @queue = :unique
93
+
94
+ def self.perform(data)
95
+ "I has a #{data}"
96
+ end
97
+
98
+ end
99
+
100
+ class OtherUnique
101
+ @queue = :unique2
102
+ @unique_jobs = true
103
+ @delayed_jobs = true
104
+ end
105
+
106
+ class DelayedJob
107
+ @queue = :delayed
108
+ @delayed_jobs = true
109
+ @unique_jobs = true
110
+ def self.perform(data)
111
+ "delayed job executing #{data.inspect}"
112
+ end
113
+ end
114
+
115
+ class NonDelayedJob
116
+ @queue = :delayed
117
+ end
118
+
119
+ #some redgreen fun
120
+ # -*- coding: utf-8 -*-
121
+ begin
122
+ require 'redgreen'
123
+ module Test
124
+ module Unit
125
+ module UI
126
+ module Console
127
+ class TestRunner
128
+ def test_started(name)
129
+ @individual_test_start_time = Time.now
130
+ output_single(name + ": ", VERBOSE)
131
+ end
132
+
133
+ def test_finished(name)
134
+ elapsed_test_time = Time.now - @individual_test_start_time
135
+ char_to_output = elapsed_test_time > 1 ? "☻" : "."
136
+ output_single(char_to_output, PROGRESS_ONLY) unless (@already_outputted)
137
+ nl(VERBOSE)
138
+ @already_outputted = false
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ # -*- coding: utf-8 -*-
147
+ class Test::Unit::UI::Console::RedGreenTestRunner < Test::Unit::UI::Console::TestRunner
148
+ def output_single(something, level=NORMAL)
149
+ return unless (output?(level))
150
+ something = case something
151
+ when '.' then Color.green('.')
152
+ when '☻' then Color.green('☻')
153
+ when 'F' then Color.red("F")
154
+ when 'E' then Color.yellow("E")
155
+ when '+' then Color.green('+')
156
+ else something
157
+ end
158
+ @io.write(something)
159
+ @io.flush
160
+ end
161
+ end
162
+ rescue LoadError
163
+ puts "consider gem install redgreen"
164
+ end
165
+
166
+
@@ -0,0 +1,302 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Resque::Worker" do
4
+ setup do
5
+ Resque.drop
6
+ Resque.before_first_fork = nil
7
+ Resque.before_fork = nil
8
+ Resque.after_fork = nil
9
+ @worker = Resque::Worker.new(:jobs)
10
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
11
+ end
12
+
13
+ test "can fail jobs" do
14
+ Resque::Job.create(:jobs, BadJob)
15
+ @worker.work(0)
16
+ assert_equal 1, Resque::Failure.count
17
+ end
18
+
19
+ test "failed jobs report exception and message" do
20
+ Resque::Job.create(:jobs, BadJobWithSyntaxError)
21
+ @worker.work(0)
22
+ assert_equal('SyntaxError', Resque::Failure.all.first['exception'])
23
+ assert_equal('Extra Bad job!', Resque::Failure.all.first['error'])
24
+ end
25
+
26
+ test "fails uncompleted jobs on exit" do
27
+ job = Resque::Job.new(:jobs, ['GoodJob', "blah"])
28
+ @worker.working_on(job)
29
+ @worker.unregister_worker
30
+ assert_equal 1, Resque::Failure.count
31
+ end
32
+
33
+ test "can peek at failed jobs" do
34
+ 10.times { Resque::Job.create(:jobs, BadJob) }
35
+ @worker.work(0)
36
+ assert_equal 10, Resque::Failure.count
37
+
38
+ assert_equal 10, Resque::Failure.all(0, 20).size
39
+ end
40
+
41
+ test "can clear failed jobs" do
42
+ Resque::Job.create(:jobs, BadJob)
43
+ @worker.work(0)
44
+ assert_equal 1, Resque::Failure.count
45
+ Resque::Failure.clear
46
+ assert_equal 0, Resque::Failure.count
47
+ end
48
+
49
+ test "catches exceptional jobs" do
50
+ Resque::Job.create(:jobs, BadJob)
51
+ Resque::Job.create(:jobs, BadJob)
52
+ @worker.process
53
+ @worker.process
54
+ @worker.process
55
+ assert_equal 2, Resque::Failure.count
56
+ end
57
+
58
+ test "can work on multiple queues" do
59
+ Resque::Job.create(:high, GoodJob)
60
+ Resque::Job.create(:critical, GoodJob)
61
+
62
+ worker = Resque::Worker.new(:critical, :high)
63
+
64
+ worker.process
65
+ assert_equal 1, Resque.size(:high)
66
+ assert_equal 0, Resque.size(:critical)
67
+
68
+ worker.process
69
+ assert_equal 0, Resque.size(:high)
70
+ end
71
+
72
+ test "can work on all queues" do
73
+ Resque::Job.create(:high, GoodJob)
74
+ Resque::Job.create(:critical, GoodJob)
75
+ Resque::Job.create(:blahblah, GoodJob)
76
+
77
+ worker = Resque::Worker.new("*")
78
+
79
+ worker.work(0)
80
+ assert_equal 0, Resque.size(:high)
81
+ assert_equal 0, Resque.size(:critical)
82
+ assert_equal 0, Resque.size(:blahblah)
83
+ end
84
+
85
+ test "processes * queues in alphabetical order" do
86
+ Resque::Job.create(:high, GoodJob)
87
+ Resque::Job.create(:critical, GoodJob)
88
+ Resque::Job.create(:blahblah, GoodJob)
89
+
90
+ worker = Resque::Worker.new("*")
91
+ processed_queues = []
92
+
93
+ worker.work(0) do |job|
94
+ processed_queues << job.queue
95
+ end
96
+
97
+ assert_equal %w( jobs high critical blahblah ).sort, processed_queues
98
+ end
99
+
100
+ test "has a unique id" do
101
+ assert_equal "#{`hostname`.chomp}:#{$$}:jobs", @worker.to_s
102
+ end
103
+
104
+ test "complains if no queues are given" do
105
+ assert_raise Resque::NoQueueError do
106
+ Resque::Worker.new
107
+ end
108
+ end
109
+
110
+ test "fails if a job class has no `perform` method" do
111
+ worker = Resque::Worker.new(:perform_less)
112
+ Resque::Job.create(:perform_less, Object)
113
+
114
+ assert_equal 0, Resque::Failure.count
115
+ worker.work(0)
116
+ assert_equal 1, Resque::Failure.count
117
+ end
118
+
119
+ test "inserts itself into the 'workers' list on startup" do
120
+ @worker.work(0) do
121
+ assert_equal @worker, Resque.workers[0]
122
+ end
123
+ end
124
+
125
+ test "removes itself from the 'workers' list on shutdown" do
126
+ @worker.work(0) do
127
+ assert_equal @worker, Resque.workers[0]
128
+ end
129
+
130
+ assert_equal [], Resque.workers
131
+ end
132
+
133
+ test "removes worker with stringified id" do
134
+ @worker.work(0) do
135
+ worker_id = Resque.workers[0].to_s
136
+ Resque.remove_worker(worker_id)
137
+ assert_equal [], Resque.workers
138
+ end
139
+ end
140
+
141
+ test "records what it is working on" do
142
+ @worker.work(0) do
143
+ task = @worker.job
144
+ task['payload'].delete "_id"
145
+ assert_equal({"args"=>[20, "/tmp"], "class"=>"SomeJob"}, task['payload'])
146
+ assert task['run_at']
147
+ assert_equal 'jobs', task['queue'].to_s
148
+ end
149
+ end
150
+
151
+ test "clears its status when not working on anything" do
152
+ @worker.work(0)
153
+ assert_equal Hash.new, @worker.job
154
+ end
155
+
156
+ test "knows when it is working" do
157
+ @worker.work(0) do
158
+ assert @worker.working?
159
+ end
160
+ end
161
+
162
+ test "knows when it is idle" do
163
+ @worker.work(0)
164
+ assert @worker.idle?
165
+ end
166
+
167
+ test "knows who is working" do
168
+ @worker.work(0) do
169
+ assert_equal [@worker], Resque.working
170
+ end
171
+ end
172
+
173
+ test "keeps track of how many jobs it has processed" do
174
+ Resque::Job.create(:jobs, BadJob)
175
+ Resque::Job.create(:jobs, BadJob)
176
+
177
+ 3.times do
178
+ job = @worker.reserve
179
+ @worker.process job
180
+ end
181
+ assert_equal 3, @worker.processed
182
+ end
183
+
184
+ test "keeps track of how many failures it has seen" do
185
+ Resque::Job.create(:jobs, BadJob)
186
+ Resque::Job.create(:jobs, BadJob)
187
+
188
+ 3.times do
189
+ job = @worker.reserve
190
+ @worker.process job
191
+ end
192
+ assert_equal 2, @worker.failed
193
+ end
194
+
195
+ test "stats are erased when the worker goes away" do
196
+ @worker.work(0)
197
+ assert_equal 0, @worker.processed
198
+ assert_equal 0, @worker.failed
199
+ end
200
+
201
+ test "knows when it started" do
202
+ time = Time.now
203
+ @worker.work(0) do
204
+ assert_equal time.to_s, @worker.started.to_s
205
+ end
206
+ end
207
+
208
+ test "knows whether it exists or not" do
209
+ @worker.work(0) do
210
+ assert Resque::Worker.exists?(@worker)
211
+ assert !Resque::Worker.exists?('blah-blah')
212
+ end
213
+ end
214
+
215
+ #this test depends on some OS-specific behavior
216
+ test "sets $0 while working" do
217
+ @worker.work(0) do
218
+ ver = Resque::Version
219
+ assert_equal "resque-#{ver}: Processing jobs since #{Time.now.to_i}"[0..$0.length-1], $0
220
+ end
221
+ end
222
+
223
+ test "can be found" do
224
+ @worker.work(0) do
225
+ found = Resque::Worker.find(@worker.to_s)
226
+ assert_equal @worker.to_s, found.to_s
227
+ assert found.working?
228
+ assert_equal @worker.job, found.job
229
+ end
230
+ end
231
+
232
+ test "doesn't find fakes" do
233
+ @worker.work(0) do
234
+ found = Resque::Worker.find('blah-blah')
235
+ assert_equal nil, found
236
+ end
237
+ end
238
+
239
+ test "cleans up dead worker info on start (crash recovery)" do
240
+ # first we fake out two dead workers
241
+ workerA = Resque::Worker.new(:jobs)
242
+ workerA.instance_variable_set(:@to_s, "#{`hostname`.chomp}:1:jobs")
243
+ workerA.register_worker
244
+
245
+ workerB = Resque::Worker.new(:high, :low)
246
+ workerB.instance_variable_set(:@to_s, "#{`hostname`.chomp}:2:high,low")
247
+ workerB.register_worker
248
+
249
+ assert_equal 2, Resque.workers.size
250
+
251
+ # then we prune them
252
+ @worker.work(0) do
253
+ assert_equal 1, Resque.workers.size
254
+ end
255
+ end
256
+
257
+ test "Processed jobs count" do
258
+ @worker.work(0)
259
+ assert_equal 1, Resque.info[:processed]
260
+ end
261
+
262
+ test "Will call a before_first_fork hook only once" do
263
+ Resque.drop
264
+ $BEFORE_FORK_CALLED = 0
265
+ Resque.before_first_fork = Proc.new { $BEFORE_FORK_CALLED += 1 }
266
+ workerA = Resque::Worker.new(:jobs)
267
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
268
+
269
+ assert_equal 0, $BEFORE_FORK_CALLED
270
+
271
+ workerA.work(0)
272
+ assert_equal 1, $BEFORE_FORK_CALLED
273
+
274
+ # TODO: Verify it's only run once. Not easy.
275
+ # workerA.work(0)
276
+ # assert_equal 1, $BEFORE_FORK_CALLED
277
+ end
278
+
279
+ test "Will call a before_fork hook before forking" do
280
+ Resque.drop
281
+ $BEFORE_FORK_CALLED = false
282
+ Resque.before_fork = Proc.new { $BEFORE_FORK_CALLED = true }
283
+ workerA = Resque::Worker.new(:jobs)
284
+
285
+ assert !$BEFORE_FORK_CALLED
286
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
287
+ workerA.work(0)
288
+ assert $BEFORE_FORK_CALLED
289
+ end
290
+
291
+ test "Will call an after_fork hook after forking" do
292
+ Resque.drop
293
+ $AFTER_FORK_CALLED = false
294
+ Resque.after_fork = Proc.new { $AFTER_FORK_CALLED = true }
295
+ workerA = Resque::Worker.new(:jobs)
296
+
297
+ assert !$AFTER_FORK_CALLED
298
+ Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
299
+ workerA.work(0)
300
+ assert $AFTER_FORK_CALLED
301
+ end
302
+ end