resque-igo 1.1

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