resque-director 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +76 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/resque/plugins/director/config.rb +39 -0
- data/lib/resque/plugins/director/lifecycle.rb +30 -0
- data/lib/resque/plugins/director/scaler.rb +72 -0
- data/lib/resque/plugins/director/worker_tracker.rb +57 -0
- data/lib/resque/plugins/director.rb +95 -0
- data/lib/resque-director.rb +7 -0
- data/resque-director.gemspec +76 -0
- data/spec/redis-test.conf +417 -0
- data/spec/resque/plugins/director/config_spec.rb +37 -0
- data/spec/resque/plugins/director/lifecycle_spec.rb +20 -0
- data/spec/resque/plugins/director/scaler_spec.rb +246 -0
- data/spec/resque/plugins/director/worker_tracker_spec.rb +137 -0
- data/spec/resque/plugins/director_spec.rb +200 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/test_job.rb +7 -0
- metadata +176 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resque::Plugins::Director::Scaler do
|
4
|
+
subject { Resque::Plugins::Director::Scaler }
|
5
|
+
|
6
|
+
before do
|
7
|
+
Resque::Plugins::Director::Config.queue = "test"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#scale_up" do
|
11
|
+
it "should start a worker on a specific queue" do
|
12
|
+
subject.should_receive(:system).with("QUEUE=test rake resque:work &")
|
13
|
+
subject.scale_up
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should start the specified number of workers on a specific queue" do
|
17
|
+
subject.should_receive(:system).twice.with("QUEUE=test rake resque:work &")
|
18
|
+
subject.scale_up(2)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not start more workers than the maximum allowed" do
|
22
|
+
Resque::Plugins::Director::Config.setup :max_workers => 1
|
23
|
+
subject.should_receive(:system).once.with("QUEUE=test rake resque:work &")
|
24
|
+
subject.scale_up(2)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should override the entire comand" do
|
28
|
+
Resque::Plugins::Director::Config.setup(:start_override => "run this")
|
29
|
+
subject.should_receive(:system).with("run this")
|
30
|
+
subject.scale_up
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#scaling" do
|
35
|
+
before do
|
36
|
+
@times_scaled = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not scale workers if last time scaled is too soon" do
|
40
|
+
Resque::Plugins::Director::Config.setup(:wait_time => 60)
|
41
|
+
2.times { subject.scaling { @times_scaled += 1 } }
|
42
|
+
@times_scaled.should == 1
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should scale workers if wait time has passed" do
|
46
|
+
Resque::Plugins::Director::Config.setup(:wait_time => 0)
|
47
|
+
2.times { subject.scaling { @times_scaled += 1 } }
|
48
|
+
@times_scaled.should == 2
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#scale_down_to_minimum" do
|
53
|
+
before do
|
54
|
+
@worker = Resque::Worker.new(:test)
|
55
|
+
Resque::Plugins::Director::Config.setup :min_workers => 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should scale workers down to the minimum" do
|
59
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
60
|
+
Process.should_receive(:kill).twice
|
61
|
+
subject.scale_down_to_minimum
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not scale if the workers are already at the minimum" do
|
65
|
+
Resque.should_receive(:workers).and_return [@worker]
|
66
|
+
Process.should_not_receive(:kill)
|
67
|
+
subject.scale_down_to_minimum
|
68
|
+
end
|
69
|
+
|
70
|
+
it "forces scaling by ignoring wait_time" do
|
71
|
+
Resque::Plugins::Director::Config.setup(:wait_time => 60, :min_workers => 2)
|
72
|
+
subject.scaling {}
|
73
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
74
|
+
Process.should_receive(:kill)
|
75
|
+
subject.scale_down_to_minimum
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#scale_down" do
|
80
|
+
before do
|
81
|
+
@worker = Resque::Worker.new(:test)
|
82
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should scale down a single worker by default" do
|
86
|
+
worker2 = Resque::Worker.new(:test)
|
87
|
+
Resque.should_receive(:workers).and_return [@worker, worker2]
|
88
|
+
|
89
|
+
Process.should_receive(:kill).once
|
90
|
+
subject.scale_down
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should scale down multiple workers" do
|
94
|
+
worker2 = Resque::Worker.new(:test)
|
95
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, worker2]
|
96
|
+
[@worker, worker2].each { |w| Process.should_receive(:kill).with("QUIT", w.pid) }
|
97
|
+
subject.scale_down(2)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should not scale down more than the minimum allowed workers" do
|
101
|
+
Resque::Plugins::Director::Config.setup :min_workers => 1
|
102
|
+
|
103
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
104
|
+
Process.should_receive(:kill).once
|
105
|
+
subject.scale_down(2)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not scale down workers on different queues" do
|
109
|
+
worker2 = Resque::Worker.new(:not_test)
|
110
|
+
@worker.stub(:pid => 1)
|
111
|
+
worker2.stub(:pid => 2)
|
112
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, worker2]
|
113
|
+
|
114
|
+
Process.should_not_receive(:kill).with("QUIT", worker2.pid)
|
115
|
+
Process.should_receive(:kill).with("QUIT", @worker.pid)
|
116
|
+
subject.scale_down
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#stop" do
|
121
|
+
before do
|
122
|
+
@worker = Resque::Worker.new(:test)
|
123
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should kill worker by sending the QUIT signal to the workers pid" do
|
127
|
+
Resque.should_receive(:workers).and_return [@worker]
|
128
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
129
|
+
|
130
|
+
Process.should_receive(:kill).with("QUIT", @worker.pid)
|
131
|
+
subject.send(:stop, tracker, 1)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should use the stop command to stop a worker if set" do
|
135
|
+
Resque::Plugins::Director::Config.setup :stop_override => "run this", :min_workers => 0
|
136
|
+
Resque.should_receive(:workers).and_return [@worker]
|
137
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
138
|
+
|
139
|
+
subject.should_receive(:system).with("run this")
|
140
|
+
Process.should_not_receive(:kill)
|
141
|
+
subject.send(:stop, tracker, 1)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "does not stop workers already set to be shutdown" do
|
145
|
+
@worker.should_receive(:shutdown?).and_return(true)
|
146
|
+
Resque.should_receive(:workers).and_return [@worker]
|
147
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
148
|
+
|
149
|
+
Process.should_not_receive(:kill).with("QUIT", @worker.pid)
|
150
|
+
subject.send(:stop, tracker, 1)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "does not kill worker processes on different machines" do
|
154
|
+
@worker.stub!(:hostname => "different_machine")
|
155
|
+
Resque.should_receive(:workers).and_return [@worker]
|
156
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
157
|
+
|
158
|
+
Process.should_not_receive(:kill).with("QUIT", @worker.pid)
|
159
|
+
subject.send(:stop, tracker, 1)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "stops workers on the same host if possible" do
|
163
|
+
@worker.stub!(:hostname => "different_machine")
|
164
|
+
worker2 = Resque::Worker.new(:test)
|
165
|
+
Resque.should_receive(:workers).and_return [@worker, worker2]
|
166
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
167
|
+
|
168
|
+
Process.should_receive(:kill).with("QUIT", worker2.pid)
|
169
|
+
subject.send(:stop, tracker, 1)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "ignores hostname if using custom stop script" do
|
173
|
+
Resque::Plugins::Director::Config.setup :stop_override => "run this", :min_workers => 0
|
174
|
+
@worker.stub!(:hostname => "different_machine")
|
175
|
+
Resque.should_receive(:workers).and_return [@worker]
|
176
|
+
tracker = Resque::Plugins::Director::WorkerTracker.new
|
177
|
+
|
178
|
+
subject.should_receive(:system).with("run this")
|
179
|
+
Process.should_not_receive(:kill)
|
180
|
+
subject.send(:stop, tracker, 1)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#scale_within_requirements" do
|
185
|
+
it "should not scale up workers if the minumum number or greater are already running" do
|
186
|
+
Resque::Worker.new(:test).register_worker
|
187
|
+
subject.should_not_receive(:scale_up)
|
188
|
+
subject.scale_within_requirements
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should scale up the minimum number of workers if non are running" do
|
192
|
+
Resque::Plugins::Director::Config.setup :min_workers => 2
|
193
|
+
subject.should_receive(:scale_up).with(2)
|
194
|
+
subject.scale_within_requirements
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should ensure at least one worker is running if min_workers is less than zero" do
|
198
|
+
Resque::Plugins::Director::Config.setup :min_workers => -10
|
199
|
+
subject.should_receive(:scale_up).with(1)
|
200
|
+
subject.scale_within_requirements
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should ensure at least one worker is running if min_workers is zero" do
|
204
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
205
|
+
subject.should_receive(:scale_up).with(1)
|
206
|
+
subject.scale_within_requirements
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should scale up the minimum number of workers if less than the minimum are running" do
|
210
|
+
Resque::Plugins::Director::Config.setup :min_workers => 2
|
211
|
+
Resque::Worker.new(:test).register_worker
|
212
|
+
subject.should_receive(:scale_up).with(1)
|
213
|
+
subject.scale_within_requirements
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should scale down the max number of workers if more than max" do
|
217
|
+
Resque::Plugins::Director::Config.setup :max_workers => 1
|
218
|
+
workers = 2.times.map { Resque::Worker.new(:test) }
|
219
|
+
Resque.should_receive(:workers).and_return(workers)
|
220
|
+
|
221
|
+
subject.should_receive(:scale_down).with(1)
|
222
|
+
subject.scale_within_requirements
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should not scale down if max_workers is zero" do
|
226
|
+
Resque::Plugins::Director::Config.setup :max_workers => 0
|
227
|
+
workers = 1.times.map { Resque::Worker.new(:test) }
|
228
|
+
Resque.should_receive(:workers).and_return(workers)
|
229
|
+
|
230
|
+
subject.should_not_receive(:scale_down)
|
231
|
+
subject.scale_within_requirements
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should ignore workers from other queues" do
|
235
|
+
Resque::Worker.new(:other).register_worker
|
236
|
+
subject.should_receive(:scale_up).with(1)
|
237
|
+
subject.scale_within_requirements
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should ignore workers on multiple queues" do
|
241
|
+
Resque::Worker.new(:test, :other).register_worker
|
242
|
+
subject.should_receive(:scale_up).with(1)
|
243
|
+
subject.scale_within_requirements
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resque::Plugins::Director::WorkerTracker do
|
4
|
+
subject { Resque::Plugins::Director::WorkerTracker }
|
5
|
+
|
6
|
+
before do
|
7
|
+
Resque::Plugins::Director::Config.queue = "test"
|
8
|
+
@worker = Resque::Worker.new(:test)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#workers" do
|
12
|
+
before do
|
13
|
+
Resque::Plugins::Director::Config.queue = "worker_test"
|
14
|
+
end
|
15
|
+
|
16
|
+
it"should return the workers for the queue" do
|
17
|
+
Resque::Worker.new(:other).register_worker
|
18
|
+
expected_worker = Resque::Worker.new(:worker_test)
|
19
|
+
expected_worker.register_worker
|
20
|
+
|
21
|
+
subject.new.workers.should == [expected_worker]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not return workers working on multiple queues" do
|
25
|
+
Resque::Worker.new(:worker_test, :other).register_worker
|
26
|
+
subject.new.workers.should be_empty
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#total_to_remove" do
|
31
|
+
it "should limit the workers to be removed to not go below minimum allowed workers" do
|
32
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
33
|
+
Resque::Plugins::Director::Config.setup :min_workers => 1
|
34
|
+
subject.new.total_to_remove(2).should == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "always keeps at least one worker" do
|
38
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
39
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
40
|
+
subject.new.total_to_remove(2).should == 2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return zero if there is only one worker working" do
|
44
|
+
Resque.should_receive(:workers).and_return [@worker]
|
45
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
46
|
+
subject.new.total_to_remove(1).should == 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
describe "#total_to_add" do
|
52
|
+
before do
|
53
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should limit the workers to be removed to not go below minimum allowed workers" do
|
57
|
+
Resque::Plugins::Director::Config.setup :max_workers => 3
|
58
|
+
subject.new.total_to_add(2).should == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should allow the workers to be removed if it stays above the minimum" do
|
62
|
+
Resque::Plugins::Director::Config.setup :max_workers => 4
|
63
|
+
subject.new.total_to_add(2).should == 2
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not limit workers added if max_workers is zero" do
|
67
|
+
Resque::Plugins::Director::Config.setup :max_workers => 0
|
68
|
+
subject.new.total_to_add(200).should == 200
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#total_for_requirements" do
|
73
|
+
it "should return the number of workers needed to meet the minimum requirement" do
|
74
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
75
|
+
Resque::Plugins::Director::Config.setup :min_workers => 4
|
76
|
+
subject.new.total_for_requirements.should == 2
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should return the number of workers needed to meet the maximum requirement" do
|
80
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
81
|
+
Resque::Plugins::Director::Config.setup :max_workers => 1
|
82
|
+
subject.new.total_for_requirements.should == -1
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return 1 no workers are running and the minimum is zero" do
|
86
|
+
Resque.should_receive(:workers).and_return []
|
87
|
+
Resque::Plugins::Director::Config.setup :min_workers => 0
|
88
|
+
subject.new.total_for_requirements.should == 1
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return 0 if number of workers is within requirements" do
|
92
|
+
Resque.should_receive(:workers).and_return [@worker, @worker]
|
93
|
+
Resque::Plugins::Director::Config.setup :min_workers => 1, :max_workers => 3
|
94
|
+
subject.new.total_for_requirements.should == 0
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#total_to_go_to_minimum" do
|
99
|
+
it "should return the number to scale down to go to the minimum" do
|
100
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
101
|
+
Resque::Plugins::Director::Config.setup :min_workers => 2
|
102
|
+
subject.new.total_to_go_to_minimum.should == 1
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return zero if already at the minimum" do
|
106
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
107
|
+
Resque::Plugins::Director::Config.setup :min_workers => 3
|
108
|
+
subject.new.total_to_go_to_minimum.should == 0
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return zero if below the minimum" do
|
112
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
113
|
+
Resque::Plugins::Director::Config.setup :min_workers => 4
|
114
|
+
subject.new.total_to_go_to_minimum.should == 0
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#initialize" do
|
119
|
+
it "sets the workers from the queue" do
|
120
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
121
|
+
subject.new.workers.should == [@worker, @worker, @worker]
|
122
|
+
end
|
123
|
+
|
124
|
+
it "does not set workers from different queues" do
|
125
|
+
other_worker = Resque::Worker.new(:other)
|
126
|
+
Resque.should_receive(:workers).and_return [@worker, other_worker, @worker]
|
127
|
+
subject.new.workers.should == [@worker, @worker]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "does not set workers that are scheduled for shutdow" do
|
131
|
+
shutdown_worker = Resque::Worker.new(:test)
|
132
|
+
shutdown_worker.shutdown
|
133
|
+
Resque.should_receive(:workers).and_return [shutdown_worker, @worker, @worker]
|
134
|
+
subject.new.workers.should == [@worker, @worker]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resque::Plugins::Director do
|
4
|
+
before do
|
5
|
+
TestJob.direct
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be a valid resque plugin" do
|
9
|
+
Resque::Plugin.lint(Resque::Plugins::Director)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#after_enqueue_scale_workers" do
|
13
|
+
it "should scale the workers to within the requirments specified" do
|
14
|
+
Resque::Worker.new(:test).register_worker
|
15
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_within_requirements)
|
16
|
+
Resque.enqueue(TestJob)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set the queue" do
|
20
|
+
Resque.enqueue(TestJob)
|
21
|
+
Resque::Plugins::Director::Config.queue.should == "test"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#after_perform_direct_workers" do
|
26
|
+
it "should scale down to the minumum workers if there are no jobs in the queue" do
|
27
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_down_to_minimum)
|
28
|
+
TestJob.after_perform_direct_workers
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not scale down if there are jobs in the queue" do
|
32
|
+
Resque.enqueue(TestJob)
|
33
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down_to_minimum)
|
34
|
+
TestJob.after_perform_direct_workers
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#on_failure_direct_workers" do
|
39
|
+
it "should scale down to the minumum workers if there are no jobs in the queue" do
|
40
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_down_to_minimum)
|
41
|
+
TestJob.on_failure_direct_workers
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not scale down if there are jobs in the queue" do
|
45
|
+
Resque.enqueue(TestJob)
|
46
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down_to_minimum)
|
47
|
+
TestJob.on_failure_direct_workers
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#before_perform_direct_workers" do
|
52
|
+
describe "with time" do
|
53
|
+
before do
|
54
|
+
@start_time = {:resdirecttime => (Time.now - 10).utc.to_i}
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set the queue if not set" do
|
58
|
+
TestJob.direct :max_time => 20
|
59
|
+
Resque::Plugins::Director::Config.queue = nil
|
60
|
+
TestJob.before_perform_direct_workers(@start_time)
|
61
|
+
Resque::Plugins::Director::Config.queue.should == "test"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not start workers if max_time is not set" do
|
65
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
66
|
+
TestJob.before_perform_direct_workers(@start_time)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not start a worker if the time since it took is less than max_time" do
|
70
|
+
TestJob.direct :max_time => 20
|
71
|
+
|
72
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
73
|
+
TestJob.before_perform_direct_workers(@start_time)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should add a worker if the time it takes the job to go through the queue is too long" do
|
77
|
+
TestJob.direct :max_time => 5
|
78
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
79
|
+
|
80
|
+
TestJob.before_perform_direct_workers(@start_time)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should remove a worker if the queue time is below half the max" do
|
84
|
+
TestJob.direct :max_time => 25
|
85
|
+
|
86
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_down)
|
87
|
+
TestJob.before_perform_direct_workers(@start_time)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "with queue length" do
|
92
|
+
it "should not start workers if max_queue is not set" do
|
93
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
94
|
+
TestJob.before_perform_direct_workers
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not start worker if the queue length is less than max_queue" do
|
98
|
+
TestJob.direct :max_queue => 2
|
99
|
+
Resque.enqueue(TestJob)
|
100
|
+
|
101
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
102
|
+
TestJob.before_perform_direct_workers
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should start worker if the queue length is greater than max_queue" do
|
106
|
+
TestJob.direct :max_queue => 1
|
107
|
+
2.times { Resque.enqueue(TestJob) }
|
108
|
+
|
109
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
110
|
+
TestJob.before_perform_direct_workers
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should remove a worker if the queue length is below half the max" do
|
114
|
+
TestJob.direct :max_queue => 4
|
115
|
+
1.times { Resque.enqueue(TestJob) }
|
116
|
+
|
117
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_down)
|
118
|
+
TestJob.before_perform_direct_workers
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "with length and time" do
|
123
|
+
|
124
|
+
before do
|
125
|
+
@start_time = {:resdirecttime => (Time.now - 10).utc.to_i}
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should add worker if only time constraint fails" do
|
129
|
+
TestJob.direct :max_time => 5, :max_queue => 2
|
130
|
+
Resque.enqueue(TestJob)
|
131
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
132
|
+
|
133
|
+
TestJob.before_perform_direct_workers(@start_time)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should add worker if only queue length constraint fails" do
|
137
|
+
TestJob.direct :max_time => 15, :max_queue => 1
|
138
|
+
2.times { Resque.enqueue(TestJob) }
|
139
|
+
|
140
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
141
|
+
TestJob.before_perform_direct_workers
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not scale down if a worker is being scaled up due to time" do
|
145
|
+
TestJob.direct :max_queue => 4, :max_time => 5
|
146
|
+
1.times { Resque.enqueue(TestJob) }
|
147
|
+
|
148
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
149
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down)
|
150
|
+
TestJob.before_perform_direct_workers(@start_time)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not scale down if a worker is being scaled up due to queue" do
|
154
|
+
TestJob.direct :max_queue => 1, :max_time => 30
|
155
|
+
2.times { Resque.enqueue(TestJob) }
|
156
|
+
|
157
|
+
Resque::Plugins::Director::Scaler.should_receive(:scale_up)
|
158
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down)
|
159
|
+
TestJob.before_perform_direct_workers
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should not scale if only one limit is met" do
|
163
|
+
TestJob.direct :max_queue => 3, :max_time => 15
|
164
|
+
1.times { Resque.enqueue(TestJob) }
|
165
|
+
|
166
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
167
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down)
|
168
|
+
TestJob.before_perform_direct_workers(@start_time)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should not scale if no configuration options are set" do
|
172
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_up)
|
173
|
+
Resque::Plugins::Director::Scaler.should_not_receive(:scale_down)
|
174
|
+
TestJob.before_perform_direct_workers
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "crazy meta custom_perform" do
|
179
|
+
it "should strip out the timestamp from the args before calling the original perform" do
|
180
|
+
TestJob.should_receive(:original_perform).with("arg")
|
181
|
+
TestJob.perform("arg", {:resdirecttime => 1234})
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should strip out timestamp if it is not a symbol" do
|
185
|
+
TestJob.should_receive(:original_perform).with("arg")
|
186
|
+
TestJob.perform("arg", {'resdirecttime' => 1234})
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should not strip out any args if timestamp does not exist" do
|
190
|
+
TestJob.should_receive(:original_perform).with("arg", {:test => 123})
|
191
|
+
TestJob.perform("arg", {:test => 123})
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should not strip out any args if timestamp does not exist" do
|
195
|
+
TestJob.should_receive(:original_perform).with("arg")
|
196
|
+
TestJob.perform("arg")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'resque'
|
5
|
+
require 'resque-director'
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
11
|
+
#
|
12
|
+
# make sure we can run redis
|
13
|
+
#
|
14
|
+
if !system("which redis-server")
|
15
|
+
puts '', "** can't find `redis-server` in your path"
|
16
|
+
puts "** add redis-server to your PATH and try again"
|
17
|
+
abort ''
|
18
|
+
end
|
19
|
+
|
20
|
+
dir = File.dirname(__FILE__)
|
21
|
+
#
|
22
|
+
# start our own redis when the tests start,
|
23
|
+
# kill it when they end
|
24
|
+
#
|
25
|
+
|
26
|
+
at_exit do
|
27
|
+
pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
|
28
|
+
puts "Killing test redis server [#{pid}]..."
|
29
|
+
`rm -f #{dir}/dump.rdb`
|
30
|
+
Process.kill("KILL", pid.to_i)
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Starting redis for testing at localhost:9736..."
|
34
|
+
`redis-server #{dir}/redis-test.conf`
|
35
|
+
Resque.redis = 'localhost:9736'
|
36
|
+
ENV['VERBOSE'] = 'true'
|
37
|
+
|
38
|
+
RSpec.configure do |config|
|
39
|
+
config.before(:each) do
|
40
|
+
Resque::Plugins::Director::Config.reset!
|
41
|
+
Resque::Plugins::Director::Scaler.stub!(:system)
|
42
|
+
Process.stub!(:kill)
|
43
|
+
Resque.redis.flushall
|
44
|
+
end
|
45
|
+
end
|