opengotham_resque 1.8.2
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.
- data/.gitignore +2 -0
- data/.kick +26 -0
- data/HISTORY.md +142 -0
- data/LICENSE +20 -0
- data/README.markdown +794 -0
- data/Rakefile +112 -0
- data/bin/resque +57 -0
- data/bin/resque-web +23 -0
- data/config.ru +14 -0
- data/deps.rip +7 -0
- data/docs/HOOKS.md +121 -0
- data/docs/PLUGINS.md +93 -0
- data/examples/async_helper.rb +31 -0
- data/examples/demo/README.markdown +71 -0
- data/examples/demo/Rakefile +8 -0
- data/examples/demo/app.rb +38 -0
- data/examples/demo/config.ru +19 -0
- data/examples/demo/job.rb +22 -0
- data/examples/god/resque.god +53 -0
- data/examples/god/stale.god +26 -0
- data/examples/instance.rb +11 -0
- data/examples/monit/resque.monit +6 -0
- data/examples/simple.rb +30 -0
- data/init.rb +1 -0
- data/lib/resque.rb +287 -0
- data/lib/resque/errors.rb +10 -0
- data/lib/resque/failure.rb +66 -0
- data/lib/resque/failure/base.rb +61 -0
- data/lib/resque/failure/hoptoad.rb +132 -0
- data/lib/resque/failure/multiple.rb +48 -0
- data/lib/resque/failure/redis.rb +40 -0
- data/lib/resque/helpers.rb +63 -0
- data/lib/resque/job.rb +207 -0
- data/lib/resque/plugin.rb +46 -0
- data/lib/resque/server.rb +201 -0
- data/lib/resque/server/public/idle.png +0 -0
- data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
- data/lib/resque/server/public/jquery.relatize_date.js +95 -0
- data/lib/resque/server/public/poll.png +0 -0
- data/lib/resque/server/public/ranger.js +67 -0
- data/lib/resque/server/public/reset.css +48 -0
- data/lib/resque/server/public/style.css +81 -0
- data/lib/resque/server/public/working.png +0 -0
- data/lib/resque/server/test_helper.rb +19 -0
- data/lib/resque/server/views/error.erb +1 -0
- data/lib/resque/server/views/failed.erb +53 -0
- data/lib/resque/server/views/key_sets.erb +20 -0
- data/lib/resque/server/views/key_string.erb +11 -0
- data/lib/resque/server/views/layout.erb +44 -0
- data/lib/resque/server/views/next_more.erb +10 -0
- data/lib/resque/server/views/overview.erb +4 -0
- data/lib/resque/server/views/queues.erb +49 -0
- data/lib/resque/server/views/stats.erb +62 -0
- data/lib/resque/server/views/workers.erb +78 -0
- data/lib/resque/server/views/working.erb +69 -0
- data/lib/resque/stat.rb +53 -0
- data/lib/resque/tasks.rb +39 -0
- data/lib/resque/version.rb +3 -0
- data/lib/resque/worker.rb +478 -0
- data/tasks/redis.rake +159 -0
- data/tasks/resque.rake +2 -0
- data/test/job_hooks_test.rb +302 -0
- data/test/job_plugins_test.rb +209 -0
- data/test/plugin_test.rb +116 -0
- data/test/redis-test.conf +132 -0
- data/test/resque-web_test.rb +54 -0
- data/test/resque_test.rb +225 -0
- data/test/test_helper.rb +111 -0
- data/test/worker_test.rb +302 -0
- metadata +199 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'resque/server/test_helper'
|
3
|
+
|
4
|
+
# Root path test
|
5
|
+
context "on GET to /" do
|
6
|
+
setup { get "/" }
|
7
|
+
|
8
|
+
test "redirect to overview" do
|
9
|
+
follow_redirect!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Global overview
|
14
|
+
context "on GET to /overview" do
|
15
|
+
setup { get "/overview" }
|
16
|
+
|
17
|
+
test "should at least display 'queues'" do
|
18
|
+
assert last_response.body.include?('Queues')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Working jobs
|
23
|
+
context "on GET to /working" do
|
24
|
+
setup { get "/working" }
|
25
|
+
|
26
|
+
should_respond_with_success
|
27
|
+
end
|
28
|
+
|
29
|
+
# Failed
|
30
|
+
context "on GET to /failed" do
|
31
|
+
setup { get "/failed" }
|
32
|
+
|
33
|
+
should_respond_with_success
|
34
|
+
end
|
35
|
+
|
36
|
+
# Stats
|
37
|
+
context "on GET to /stats/resque" do
|
38
|
+
setup { get "/stats/resque" }
|
39
|
+
|
40
|
+
should_respond_with_success
|
41
|
+
end
|
42
|
+
|
43
|
+
context "on GET to /stats/redis" do
|
44
|
+
setup { get "/stats/redis" }
|
45
|
+
|
46
|
+
should_respond_with_success
|
47
|
+
end
|
48
|
+
|
49
|
+
context "on GET to /stats/resque" do
|
50
|
+
setup { get "/stats/keys" }
|
51
|
+
|
52
|
+
should_respond_with_success
|
53
|
+
end
|
54
|
+
|
data/test/resque_test.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
context "Resque" do
|
4
|
+
setup do
|
5
|
+
Resque.redis.flushall
|
6
|
+
|
7
|
+
Resque.push(:people, { 'name' => 'chris' })
|
8
|
+
Resque.push(:people, { 'name' => 'bob' })
|
9
|
+
Resque.push(:people, { 'name' => 'mark' })
|
10
|
+
end
|
11
|
+
|
12
|
+
test "can put jobs on a queue" do
|
13
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
14
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
15
|
+
end
|
16
|
+
|
17
|
+
test "can grab jobs off a queue" do
|
18
|
+
Resque::Job.create(:jobs, 'some-job', 20, '/tmp')
|
19
|
+
|
20
|
+
job = Resque.reserve(:jobs)
|
21
|
+
|
22
|
+
assert_kind_of Resque::Job, job
|
23
|
+
assert_equal SomeJob, job.payload_class
|
24
|
+
assert_equal 20, job.args[0]
|
25
|
+
assert_equal '/tmp', job.args[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
test "can re-queue jobs" do
|
29
|
+
Resque::Job.create(:jobs, 'some-job', 20, '/tmp')
|
30
|
+
|
31
|
+
job = Resque.reserve(:jobs)
|
32
|
+
job.recreate
|
33
|
+
|
34
|
+
assert_equal job, Resque.reserve(:jobs)
|
35
|
+
end
|
36
|
+
|
37
|
+
test "can put jobs on a queue by way of an ivar" do
|
38
|
+
assert_equal 0, Resque.size(:ivar)
|
39
|
+
assert Resque.enqueue(SomeIvarJob, 20, '/tmp')
|
40
|
+
assert Resque.enqueue(SomeIvarJob, 20, '/tmp')
|
41
|
+
|
42
|
+
job = Resque.reserve(:ivar)
|
43
|
+
|
44
|
+
assert_kind_of Resque::Job, job
|
45
|
+
assert_equal SomeIvarJob, job.payload_class
|
46
|
+
assert_equal 20, job.args[0]
|
47
|
+
assert_equal '/tmp', job.args[1]
|
48
|
+
|
49
|
+
assert Resque.reserve(:ivar)
|
50
|
+
assert_equal nil, Resque.reserve(:ivar)
|
51
|
+
end
|
52
|
+
|
53
|
+
test "can remove jobs from a queue by way of an ivar" do
|
54
|
+
assert_equal 0, Resque.size(:ivar)
|
55
|
+
assert Resque.enqueue(SomeIvarJob, 20, '/tmp')
|
56
|
+
assert Resque.enqueue(SomeIvarJob, 30, '/tmp')
|
57
|
+
assert Resque.enqueue(SomeIvarJob, 20, '/tmp')
|
58
|
+
assert Resque::Job.create(:ivar, 'blah-job', 20, '/tmp')
|
59
|
+
assert Resque.enqueue(SomeIvarJob, 20, '/tmp')
|
60
|
+
assert_equal 5, Resque.size(:ivar)
|
61
|
+
|
62
|
+
assert Resque.dequeue(SomeIvarJob, 30, '/tmp')
|
63
|
+
assert_equal 4, Resque.size(:ivar)
|
64
|
+
assert Resque.dequeue(SomeIvarJob)
|
65
|
+
assert_equal 1, Resque.size(:ivar)
|
66
|
+
end
|
67
|
+
|
68
|
+
test "jobs have a nice #inspect" do
|
69
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
70
|
+
job = Resque.reserve(:jobs)
|
71
|
+
assert_equal '(Job{jobs} | SomeJob | [20, "/tmp"])', job.inspect
|
72
|
+
end
|
73
|
+
|
74
|
+
test "jobs can be destroyed" do
|
75
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
76
|
+
assert Resque::Job.create(:jobs, 'BadJob', 20, '/tmp')
|
77
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
78
|
+
assert Resque::Job.create(:jobs, 'BadJob', 30, '/tmp')
|
79
|
+
assert Resque::Job.create(:jobs, 'BadJob', 20, '/tmp')
|
80
|
+
|
81
|
+
assert_equal 5, Resque.size(:jobs)
|
82
|
+
assert_equal 2, Resque::Job.destroy(:jobs, 'SomeJob')
|
83
|
+
assert_equal 3, Resque.size(:jobs)
|
84
|
+
assert_equal 1, Resque::Job.destroy(:jobs, 'BadJob', 30, '/tmp')
|
85
|
+
assert_equal 2, Resque.size(:jobs)
|
86
|
+
end
|
87
|
+
|
88
|
+
test "jobs can test for equality" do
|
89
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
90
|
+
assert Resque::Job.create(:jobs, 'some-job', 20, '/tmp')
|
91
|
+
assert_equal Resque.reserve(:jobs), Resque.reserve(:jobs)
|
92
|
+
|
93
|
+
assert Resque::Job.create(:jobs, 'SomeMethodJob', 20, '/tmp')
|
94
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
95
|
+
assert_not_equal Resque.reserve(:jobs), Resque.reserve(:jobs)
|
96
|
+
|
97
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
|
98
|
+
assert Resque::Job.create(:jobs, 'SomeJob', 30, '/tmp')
|
99
|
+
assert_not_equal Resque.reserve(:jobs), Resque.reserve(:jobs)
|
100
|
+
end
|
101
|
+
|
102
|
+
test "can put jobs on a queue by way of a method" do
|
103
|
+
assert_equal 0, Resque.size(:method)
|
104
|
+
assert Resque.enqueue(SomeMethodJob, 20, '/tmp')
|
105
|
+
assert Resque.enqueue(SomeMethodJob, 20, '/tmp')
|
106
|
+
|
107
|
+
job = Resque.reserve(:method)
|
108
|
+
|
109
|
+
assert_kind_of Resque::Job, job
|
110
|
+
assert_equal SomeMethodJob, job.payload_class
|
111
|
+
assert_equal 20, job.args[0]
|
112
|
+
assert_equal '/tmp', job.args[1]
|
113
|
+
|
114
|
+
assert Resque.reserve(:method)
|
115
|
+
assert_equal nil, Resque.reserve(:method)
|
116
|
+
end
|
117
|
+
|
118
|
+
test "needs to infer a queue with enqueue" do
|
119
|
+
assert_raises Resque::NoQueueError do
|
120
|
+
Resque.enqueue(SomeJob, 20, '/tmp')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
test "can put items on a queue" do
|
125
|
+
assert Resque.push(:people, { 'name' => 'jon' })
|
126
|
+
end
|
127
|
+
|
128
|
+
test "can pull items off a queue" do
|
129
|
+
assert_equal({ 'name' => 'chris' }, Resque.pop(:people))
|
130
|
+
assert_equal({ 'name' => 'bob' }, Resque.pop(:people))
|
131
|
+
assert_equal({ 'name' => 'mark' }, Resque.pop(:people))
|
132
|
+
assert_equal nil, Resque.pop(:people)
|
133
|
+
end
|
134
|
+
|
135
|
+
test "knows how big a queue is" do
|
136
|
+
assert_equal 3, Resque.size(:people)
|
137
|
+
|
138
|
+
assert_equal({ 'name' => 'chris' }, Resque.pop(:people))
|
139
|
+
assert_equal 2, Resque.size(:people)
|
140
|
+
|
141
|
+
assert_equal({ 'name' => 'bob' }, Resque.pop(:people))
|
142
|
+
assert_equal({ 'name' => 'mark' }, Resque.pop(:people))
|
143
|
+
assert_equal 0, Resque.size(:people)
|
144
|
+
end
|
145
|
+
|
146
|
+
test "can peek at a queue" do
|
147
|
+
assert_equal({ 'name' => 'chris' }, Resque.peek(:people))
|
148
|
+
assert_equal 3, Resque.size(:people)
|
149
|
+
end
|
150
|
+
|
151
|
+
test "can peek multiple items on a queue" do
|
152
|
+
assert_equal({ 'name' => 'bob' }, Resque.peek(:people, 1, 1))
|
153
|
+
|
154
|
+
assert_equal([{ 'name' => 'bob' }, { 'name' => 'mark' }], Resque.peek(:people, 1, 2))
|
155
|
+
assert_equal([{ 'name' => 'chris' }, { 'name' => 'bob' }], Resque.peek(:people, 0, 2))
|
156
|
+
assert_equal([{ 'name' => 'chris' }, { 'name' => 'bob' }, { 'name' => 'mark' }], Resque.peek(:people, 0, 3))
|
157
|
+
assert_equal({ 'name' => 'mark' }, Resque.peek(:people, 2, 1))
|
158
|
+
assert_equal nil, Resque.peek(:people, 3)
|
159
|
+
assert_equal [], Resque.peek(:people, 3, 2)
|
160
|
+
end
|
161
|
+
|
162
|
+
test "knows what queues it is managing" do
|
163
|
+
assert_equal %w( people ), Resque.queues
|
164
|
+
Resque.push(:cars, { 'make' => 'bmw' })
|
165
|
+
assert_equal %w( cars people ), Resque.queues
|
166
|
+
end
|
167
|
+
|
168
|
+
test "queues are always a list" do
|
169
|
+
Resque.redis.flushall
|
170
|
+
assert_equal [], Resque.queues
|
171
|
+
end
|
172
|
+
|
173
|
+
test "can delete a queue" do
|
174
|
+
Resque.push(:cars, { 'make' => 'bmw' })
|
175
|
+
assert_equal %w( cars people ), Resque.queues
|
176
|
+
Resque.remove_queue(:people)
|
177
|
+
assert_equal %w( cars ), Resque.queues
|
178
|
+
assert_equal nil, Resque.pop(:people)
|
179
|
+
end
|
180
|
+
|
181
|
+
test "keeps track of resque keys" do
|
182
|
+
assert_equal ["queue:people", "queues"], Resque.keys
|
183
|
+
end
|
184
|
+
|
185
|
+
test "badly wants a class name, too" do
|
186
|
+
assert_raises Resque::NoClassError do
|
187
|
+
Resque::Job.create(:jobs, nil)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
test "keeps stats" do
|
192
|
+
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
|
193
|
+
Resque::Job.create(:jobs, BadJob)
|
194
|
+
Resque::Job.create(:jobs, GoodJob)
|
195
|
+
|
196
|
+
Resque::Job.create(:others, GoodJob)
|
197
|
+
Resque::Job.create(:others, GoodJob)
|
198
|
+
|
199
|
+
stats = Resque.info
|
200
|
+
assert_equal 8, stats[:pending]
|
201
|
+
|
202
|
+
@worker = Resque::Worker.new(:jobs)
|
203
|
+
@worker.register_worker
|
204
|
+
2.times { @worker.process }
|
205
|
+
|
206
|
+
job = @worker.reserve
|
207
|
+
@worker.working_on job
|
208
|
+
|
209
|
+
stats = Resque.info
|
210
|
+
assert_equal 1, stats[:working]
|
211
|
+
assert_equal 1, stats[:workers]
|
212
|
+
|
213
|
+
@worker.done_working
|
214
|
+
|
215
|
+
stats = Resque.info
|
216
|
+
assert_equal 3, stats[:queues]
|
217
|
+
assert_equal 3, stats[:processed]
|
218
|
+
assert_equal 1, stats[:failed]
|
219
|
+
assert_equal ['localhost:9736'], stats[:servers]
|
220
|
+
end
|
221
|
+
|
222
|
+
test "decode bad json" do
|
223
|
+
assert_nil Resque.decode("{\"error\":\"Module not found \\u002\"}")
|
224
|
+
end
|
225
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,111 @@
|
|
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
|
+
|
9
|
+
#
|
10
|
+
# make sure we can run redis
|
11
|
+
#
|
12
|
+
|
13
|
+
if !system("which redis-server")
|
14
|
+
puts '', "** can't find `redis-server` in your path"
|
15
|
+
puts "** try running `sudo rake install`"
|
16
|
+
abort ''
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# start our own redis when the tests start,
|
22
|
+
# kill it when they end
|
23
|
+
#
|
24
|
+
|
25
|
+
at_exit do
|
26
|
+
next if $!
|
27
|
+
|
28
|
+
if defined?(MiniTest)
|
29
|
+
exit_code = MiniTest::Unit.new.run(ARGV)
|
30
|
+
else
|
31
|
+
exit_code = Test::Unit::AutoRunner.run
|
32
|
+
end
|
33
|
+
|
34
|
+
pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
|
35
|
+
puts "Killing test redis server..."
|
36
|
+
`rm -f #{dir}/dump.rdb`
|
37
|
+
Process.kill("KILL", pid.to_i)
|
38
|
+
exit exit_code
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Starting redis for testing at localhost:9736..."
|
42
|
+
`redis-server #{dir}/redis-test.conf`
|
43
|
+
Resque.redis = 'localhost:9736'
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
# test/spec/mini 3
|
48
|
+
# http://gist.github.com/25455
|
49
|
+
# chris@ozmm.org
|
50
|
+
#
|
51
|
+
def context(*args, &block)
|
52
|
+
return super unless (name = args.first) && block
|
53
|
+
require 'test/unit'
|
54
|
+
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
55
|
+
def self.test(name, &block)
|
56
|
+
define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
|
57
|
+
end
|
58
|
+
def self.xtest(*args) end
|
59
|
+
def self.setup(&block) define_method(:setup, &block) end
|
60
|
+
def self.teardown(&block) define_method(:teardown, &block) end
|
61
|
+
end
|
62
|
+
(class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
|
63
|
+
klass.class_eval &block
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Helper to perform job classes
|
68
|
+
#
|
69
|
+
module PerformJob
|
70
|
+
def perform_job(klass, *args)
|
71
|
+
resque_job = Resque::Job.new(:testqueue, 'class' => klass, 'args' => args)
|
72
|
+
resque_job.perform
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# fixture classes
|
78
|
+
#
|
79
|
+
|
80
|
+
class SomeJob
|
81
|
+
def self.perform(repo_id, path)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class SomeIvarJob < SomeJob
|
86
|
+
@queue = :ivar
|
87
|
+
end
|
88
|
+
|
89
|
+
class SomeMethodJob < SomeJob
|
90
|
+
def self.queue
|
91
|
+
:method
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class BadJob
|
96
|
+
def self.perform
|
97
|
+
raise "Bad job!"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class GoodJob
|
102
|
+
def self.perform(name)
|
103
|
+
"Good job, #{name}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class BadJobWithSyntaxError
|
108
|
+
def self.perform
|
109
|
+
raise SyntaxError, "Extra Bad job!"
|
110
|
+
end
|
111
|
+
end
|
data/test/worker_test.rb
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/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 "fails uncompleted jobs on exit" do
|
29
|
+
job = Resque::Job.new(:jobs, [GoodJob, "blah"])
|
30
|
+
@worker.working_on(job)
|
31
|
+
@worker.unregister_worker
|
32
|
+
assert_equal 1, Resque::Failure.count
|
33
|
+
end
|
34
|
+
|
35
|
+
test "can peek at failed jobs" do
|
36
|
+
10.times { Resque::Job.create(:jobs, BadJob) }
|
37
|
+
@worker.work(0)
|
38
|
+
assert_equal 10, Resque::Failure.count
|
39
|
+
|
40
|
+
assert_equal 10, Resque::Failure.all(0, 20).size
|
41
|
+
end
|
42
|
+
|
43
|
+
test "can clear failed jobs" do
|
44
|
+
Resque::Job.create(:jobs, BadJob)
|
45
|
+
@worker.work(0)
|
46
|
+
assert_equal 1, Resque::Failure.count
|
47
|
+
Resque::Failure.clear
|
48
|
+
assert_equal 0, Resque::Failure.count
|
49
|
+
end
|
50
|
+
|
51
|
+
test "catches exceptional jobs" do
|
52
|
+
Resque::Job.create(:jobs, BadJob)
|
53
|
+
Resque::Job.create(:jobs, BadJob)
|
54
|
+
@worker.process
|
55
|
+
@worker.process
|
56
|
+
@worker.process
|
57
|
+
assert_equal 2, Resque::Failure.count
|
58
|
+
end
|
59
|
+
|
60
|
+
test "can work on multiple queues" do
|
61
|
+
Resque::Job.create(:high, GoodJob)
|
62
|
+
Resque::Job.create(:critical, GoodJob)
|
63
|
+
|
64
|
+
worker = Resque::Worker.new(:critical, :high)
|
65
|
+
|
66
|
+
worker.process
|
67
|
+
assert_equal 1, Resque.size(:high)
|
68
|
+
assert_equal 0, Resque.size(:critical)
|
69
|
+
|
70
|
+
worker.process
|
71
|
+
assert_equal 0, Resque.size(:high)
|
72
|
+
end
|
73
|
+
|
74
|
+
test "can work on all queues" do
|
75
|
+
Resque::Job.create(:high, GoodJob)
|
76
|
+
Resque::Job.create(:critical, GoodJob)
|
77
|
+
Resque::Job.create(:blahblah, GoodJob)
|
78
|
+
|
79
|
+
worker = Resque::Worker.new("*")
|
80
|
+
|
81
|
+
worker.work(0)
|
82
|
+
assert_equal 0, Resque.size(:high)
|
83
|
+
assert_equal 0, Resque.size(:critical)
|
84
|
+
assert_equal 0, Resque.size(:blahblah)
|
85
|
+
end
|
86
|
+
|
87
|
+
test "processes * queues in alphabetical order" do
|
88
|
+
Resque::Job.create(:high, GoodJob)
|
89
|
+
Resque::Job.create(:critical, GoodJob)
|
90
|
+
Resque::Job.create(:blahblah, GoodJob)
|
91
|
+
|
92
|
+
worker = Resque::Worker.new("*")
|
93
|
+
processed_queues = []
|
94
|
+
|
95
|
+
worker.work(0) do |job|
|
96
|
+
processed_queues << job.queue
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal %w( jobs high critical blahblah ).sort, processed_queues
|
100
|
+
end
|
101
|
+
|
102
|
+
test "has a unique id" do
|
103
|
+
assert_equal "#{`hostname`.chomp}:#{$$}:jobs", @worker.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
test "complains if no queues are given" do
|
107
|
+
assert_raise Resque::NoQueueError do
|
108
|
+
Resque::Worker.new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
test "fails if a job class has no `perform` method" do
|
113
|
+
worker = Resque::Worker.new(:perform_less)
|
114
|
+
Resque::Job.create(:perform_less, Object)
|
115
|
+
|
116
|
+
assert_equal 0, Resque::Failure.count
|
117
|
+
worker.work(0)
|
118
|
+
assert_equal 1, Resque::Failure.count
|
119
|
+
end
|
120
|
+
|
121
|
+
test "inserts itself into the 'workers' list on startup" do
|
122
|
+
@worker.work(0) do
|
123
|
+
assert_equal @worker, Resque.workers[0]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
test "removes itself from the 'workers' list on shutdown" do
|
128
|
+
@worker.work(0) do
|
129
|
+
assert_equal @worker, Resque.workers[0]
|
130
|
+
end
|
131
|
+
|
132
|
+
assert_equal [], Resque.workers
|
133
|
+
end
|
134
|
+
|
135
|
+
test "removes worker with stringified id" do
|
136
|
+
@worker.work(0) do
|
137
|
+
worker_id = Resque.workers[0].to_s
|
138
|
+
Resque.remove_worker(worker_id)
|
139
|
+
assert_equal [], Resque.workers
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
test "records what it is working on" do
|
144
|
+
@worker.work(0) do
|
145
|
+
task = @worker.job
|
146
|
+
assert_equal({"args"=>[20, "/tmp"], "class"=>"SomeJob"}, task['payload'])
|
147
|
+
assert task['run_at']
|
148
|
+
assert_equal 'jobs', task['queue']
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
test "clears its status when not working on anything" do
|
153
|
+
@worker.work(0)
|
154
|
+
assert_equal Hash.new, @worker.job
|
155
|
+
end
|
156
|
+
|
157
|
+
test "knows when it is working" do
|
158
|
+
@worker.work(0) do
|
159
|
+
assert @worker.working?
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
test "knows when it is idle" do
|
164
|
+
@worker.work(0)
|
165
|
+
assert @worker.idle?
|
166
|
+
end
|
167
|
+
|
168
|
+
test "knows who is working" do
|
169
|
+
@worker.work(0) do
|
170
|
+
assert_equal [@worker], Resque.working
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
test "keeps track of how many jobs it has processed" do
|
175
|
+
Resque::Job.create(:jobs, BadJob)
|
176
|
+
Resque::Job.create(:jobs, BadJob)
|
177
|
+
|
178
|
+
3.times do
|
179
|
+
job = @worker.reserve
|
180
|
+
@worker.process job
|
181
|
+
end
|
182
|
+
assert_equal 3, @worker.processed
|
183
|
+
end
|
184
|
+
|
185
|
+
test "keeps track of how many failures it has seen" do
|
186
|
+
Resque::Job.create(:jobs, BadJob)
|
187
|
+
Resque::Job.create(:jobs, BadJob)
|
188
|
+
|
189
|
+
3.times do
|
190
|
+
job = @worker.reserve
|
191
|
+
@worker.process job
|
192
|
+
end
|
193
|
+
assert_equal 2, @worker.failed
|
194
|
+
end
|
195
|
+
|
196
|
+
test "stats are erased when the worker goes away" do
|
197
|
+
@worker.work(0)
|
198
|
+
assert_equal 0, @worker.processed
|
199
|
+
assert_equal 0, @worker.failed
|
200
|
+
end
|
201
|
+
|
202
|
+
test "knows when it started" do
|
203
|
+
time = Time.now
|
204
|
+
@worker.work(0) do
|
205
|
+
assert_equal time.to_s, @worker.started.to_s
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
test "knows whether it exists or not" do
|
210
|
+
@worker.work(0) do
|
211
|
+
assert Resque::Worker.exists?(@worker)
|
212
|
+
assert !Resque::Worker.exists?('blah-blah')
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
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
|
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.redis.flushall
|
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.redis.flushall
|
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.redis.flushall
|
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
|