resque-director 2.2.2 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +41 -0
- data/README.rdoc +4 -4
- data/VERSION +1 -1
- data/lib/resque/plugins/director/scaler.rb +11 -14
- data/lib/resque/plugins/director/worker_tracker.rb +42 -46
- data/resque-director.gemspec +4 -4
- data/spec/resque/plugins/director/scaler_spec.rb +24 -30
- data/spec/resque/plugins/director/worker_tracker_spec.rb +52 -58
- metadata +13 -13
- data/.document +0 -5
data/HISTORY.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## 2.2.2 (2011-09-09)
|
2
|
+
|
3
|
+
* Bugfix: ignore wait_time when scaling to be within limits
|
4
|
+
|
5
|
+
## 2.2.1 (2011-09-07)
|
6
|
+
|
7
|
+
* Bugfix: make compatible with ruby 1.9
|
8
|
+
|
9
|
+
## 2.2.0 (2011-09-07)
|
10
|
+
|
11
|
+
* Added scaling workers working on multiple queues
|
12
|
+
|
13
|
+
## 2.1.1 (2011-09-02)
|
14
|
+
|
15
|
+
* Dont update last scaled time if start/stop block returns false
|
16
|
+
|
17
|
+
## 2.1.0 (2011-09-01)
|
18
|
+
|
19
|
+
* Change default log level to debug
|
20
|
+
* Make gem compatible with resque ~> 1.10
|
21
|
+
* add `no_enqueue_scale` option
|
22
|
+
* scale within requirements before perform
|
23
|
+
|
24
|
+
## 2.0.0 (2011-08-24)
|
25
|
+
|
26
|
+
* Must extend the plugin instead of include
|
27
|
+
* Modify resque's push/pop functionality to track time
|
28
|
+
* Start/stop override lambdas accept queue-name as an argument
|
29
|
+
|
30
|
+
## 1.1.0 (2011-08-23)
|
31
|
+
|
32
|
+
* Added logging options
|
33
|
+
* Bugfix: don't raise error when killing worker process
|
34
|
+
|
35
|
+
## 1.0.1 (2011-08-20)
|
36
|
+
|
37
|
+
* Bugfix: Dont append timestamp argument to resque job for non directed jobs
|
38
|
+
|
39
|
+
## 1.0.0 (2011-08-20)
|
40
|
+
|
41
|
+
* 1.0 release.
|
data/README.rdoc
CHANGED
@@ -4,7 +4,7 @@ Resque Director is a plugin for the Resque queueing system (http://github.com/de
|
|
4
4
|
|
5
5
|
==About
|
6
6
|
|
7
|
-
|
7
|
+
Resque-director is useful for when you are managing a large number of workers and don't want to waste resources keeping all of them waiting when they are not being used. For jobs that are high priority or time sensitive you can have it autoscale workers based on how long it takes to go through the queue, or how big the queue becomes. In queues where the influx of jobs can change dramatically from time to time, resque director automatically scales more workers during the times when the queue is filling up more quickly, and less in the opposite scenario. Different queues can be given different directions as well.
|
8
8
|
|
9
9
|
== Usage
|
10
10
|
|
@@ -27,7 +27,7 @@ For Example:
|
|
27
27
|
|
28
28
|
<b>max_workers</b>:: specifies the maximum number of workers running at any point in time. It will never start more than the maximum number of workers. If anything less than or equal to zero is specified as the maximum it will be treated as if there is no maximum, and theoretically an infinite number of workers could be started. The default is 0.
|
29
29
|
|
30
|
-
<b>max_time</b>:: the maximum time in seconds that a job takes to
|
30
|
+
<b>max_time</b>:: the maximum time in seconds that a job takes to go through the queue, if it takes longer than this time then a worker is started. If anything less than or equal to zero is specified as the maximum time, this field will be ignored. The default is 0.
|
31
31
|
|
32
32
|
<b>max_queue</b>:: the maximum jobs that can build up in a queue, if more than this number of jobs build up then a worker is started. If anything less than or equal to zero is specified as the maximum queue, this field will be ignored. The default is 0.
|
33
33
|
|
@@ -35,7 +35,7 @@ For Example:
|
|
35
35
|
|
36
36
|
=== Conditions For Starting Workers
|
37
37
|
|
38
|
-
A worker will be started if the queue length is greater than <b>max_queue</b> or if the time it takes a job to go through the queue is greater than <b>max_time</b>. Also a worker will only be started if the time since the last scaling is greater than <b>wait_time</b>. Workers will not be started if there are already the <b>max_workers</b> number of workers. By default resque-director allows you to have zero
|
38
|
+
A worker will be started if the queue length is greater than <b>max_queue</b> or if the time it takes a job to go through the queue is greater than <b>max_time</b>. Also a worker will only be started if the time since the last scaling is greater than <b>wait_time</b>. Workers will not be started if there are already the <b>max_workers</b> number of workers. By default resque-director allows you to have zero workers running, when a job is enqueued then workers will be scaled within the max/min requirements you set. If there is not a single worker running, then the minimum number of workers will be scaled up (one worker will be scaled up if the minimum is zero).
|
39
39
|
|
40
40
|
=== Conditions For Removing Workers
|
41
41
|
|
@@ -52,7 +52,7 @@ The above options are plenty to handle the basic scaling of workers. The options
|
|
52
52
|
|
53
53
|
=== Start/Stop Options
|
54
54
|
|
55
|
-
<b>start_override</b>:: You can set this option if you want to override the way to start a worker. This option takes a lambda closure that accepts the queue as an argument, the block you pass in will be responsible for starting a <em>SINGLE</em> worker allowing you to fully customize the starting of a worker. If your block returns false then that signifies that a worker was not started and the last scaled time will not be set. The default way a worker is started is with the system command: <tt>QUEUE=queue_name rake resque:work &</tt> where "queue_name" is the queue on which the job is running.
|
55
|
+
<b>start_override</b>:: You can set this option if you want to override the way to start a worker. This option takes a lambda closure that accepts the queue as an argument, the block you pass in will be responsible for starting a <em>SINGLE</em> worker allowing you to fully customize the starting of a worker. If your block returns false then that signifies that a worker was not started and the last scaled time will not be set. The default way a worker is started is with the system command: "<tt>QUEUE=queue_name rake resque:work &</tt>" where "queue_name" is the queue on which the job is running.
|
56
56
|
|
57
57
|
<b>stop_override</b>:: You can set this option if you want to override the way to stop a worker. This option takes a lambda closure that accepts the queue as an argument, the block you pass in will be responsible for stopping a <em>SINGLE</em> worker allowing you to fully customize the stopping of a worker. If your block returns false then that signifies that a worker was not stopped and the last scaled time will not be set. The default way a worker is stopped is that a QUIT signal is sent to a worker process.
|
58
58
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.2.
|
1
|
+
2.2.3
|
@@ -5,33 +5,30 @@ module Resque
|
|
5
5
|
class << self
|
6
6
|
|
7
7
|
def scale_up(number_of_workers=1)
|
8
|
-
number_of_workers = WorkerTracker.
|
8
|
+
number_of_workers = WorkerTracker.total_to_add(number_of_workers)
|
9
9
|
scaling(number_of_workers) do
|
10
10
|
start(number_of_workers)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def scale_down(number_of_workers=1)
|
15
|
-
|
16
|
-
number_of_workers = tracker.total_to_remove(number_of_workers)
|
15
|
+
number_of_workers = WorkerTracker.total_to_remove(number_of_workers)
|
17
16
|
scaling(number_of_workers) do
|
18
|
-
stop(
|
17
|
+
stop(number_of_workers)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
def scale_down_to_minimum
|
23
|
-
|
24
|
-
number_of_workers
|
25
|
-
stop(tracker, number_of_workers)
|
22
|
+
number_of_workers = WorkerTracker.total_to_go_to_minimum
|
23
|
+
stop(number_of_workers)
|
26
24
|
end
|
27
25
|
|
28
26
|
def scale_within_requirements
|
29
|
-
|
30
|
-
number_of_workers = tracker.total_for_requirements
|
27
|
+
number_of_workers = WorkerTracker.total_for_requirements
|
31
28
|
if number_of_workers > 0
|
32
29
|
set_last_scaled unless start(number_of_workers) == false
|
33
30
|
elsif number_of_workers < 0
|
34
|
-
set_last_scaled unless stop(
|
31
|
+
set_last_scaled unless stop(number_of_workers * -1) == false
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
@@ -59,10 +56,10 @@ module Resque
|
|
59
56
|
start_default(number_of_workers)
|
60
57
|
end
|
61
58
|
|
62
|
-
def stop(
|
59
|
+
def stop(number_of_workers)
|
63
60
|
Config.log("stopping #{number_of_workers} workers on queue:#{Config.queue}") if number_of_workers > 0
|
64
61
|
return override(number_of_workers, Config.stop_override) if Config.stop_override
|
65
|
-
stop_default(
|
62
|
+
stop_default(number_of_workers)
|
66
63
|
end
|
67
64
|
|
68
65
|
def override(number_of_workers, override_block)
|
@@ -73,8 +70,8 @@ module Resque
|
|
73
70
|
number_of_workers.times { system("QUEUE=#{[Config.queue].flatten.join(",")} rake resque:work &") }
|
74
71
|
end
|
75
72
|
|
76
|
-
def stop_default(
|
77
|
-
worker_pids =
|
73
|
+
def stop_default(number_of_workers)
|
74
|
+
worker_pids = WorkerTracker.valid_worker_pids[0...number_of_workers]
|
78
75
|
worker_pids.each do |pid|
|
79
76
|
Process.kill("QUIT", pid) rescue nil
|
80
77
|
end
|
@@ -2,62 +2,58 @@ module Resque
|
|
2
2
|
module Plugins
|
3
3
|
module Director
|
4
4
|
class WorkerTracker
|
5
|
-
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@workers = current_workers
|
9
|
-
@number_working = @workers.size
|
10
|
-
end
|
5
|
+
class << self
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
def total_for_requirements
|
8
|
+
start_number = workers_to_start
|
9
|
+
stop_number = workers_to_stop
|
10
|
+
return start_number if start_number > 0
|
11
|
+
return stop_number if stop_number < 0
|
12
|
+
0
|
13
|
+
end
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
def total_to_go_to_minimum
|
16
|
+
to_minimum = current_workers.size - Config.min_workers
|
17
|
+
to_minimum > 0 ? to_minimum : 0
|
18
|
+
end
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
def total_to_add(number_to_start)
|
21
|
+
return number_to_start if Config.max_workers <= 0
|
22
|
+
scale_limit = Config.max_workers - current_workers.size
|
23
|
+
Config.log("WORKER MAX REACHED: wanted to start #{number_to_start} workers on queue:#{Config.queue}") if scale_limit <= 0
|
24
|
+
number_to_start > scale_limit ? scale_limit : number_to_start
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
def total_to_remove(number_to_stop)
|
28
|
+
min_workers = Config.min_workers <= 0 ? 1 : Config.min_workers
|
29
|
+
scale_limit = current_workers.size - min_workers
|
30
|
+
if scale_limit <= 0 && Config.min_workers > 0
|
31
|
+
Config.log("WORKER MIN REACHED: wanted to stop #{number_to_stop} workers on queue:#{Config.queue}")
|
32
|
+
end
|
33
|
+
number_to_stop > scale_limit ? scale_limit : number_to_stop
|
37
34
|
end
|
38
|
-
number_to_stop > scale_limit ? scale_limit : number_to_stop
|
39
|
-
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
def valid_worker_pids
|
37
|
+
valid_workers = current_workers.select{|w| w.hostname == `hostname`.chomp}
|
38
|
+
valid_workers.map{|worker| worker.to_s.split(":")[1].to_i }
|
39
|
+
end
|
45
40
|
|
46
|
-
|
41
|
+
private
|
47
42
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
def workers_to_start
|
44
|
+
min_workers = Config.min_workers <= 0 ? 1 : Config.min_workers
|
45
|
+
min_workers - current_workers.size
|
46
|
+
end
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
48
|
+
def workers_to_stop
|
49
|
+
return 0 if Config.max_workers <= 0
|
50
|
+
Config.max_workers - current_workers.size
|
51
|
+
end
|
57
52
|
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
def current_workers
|
54
|
+
Resque.workers.select do |w|
|
55
|
+
w.queues.map(&:to_s) == [Config.queue].flatten.map(&:to_s) && !w.shutdown?
|
56
|
+
end
|
61
57
|
end
|
62
58
|
end
|
63
59
|
end
|
data/resque-director.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{resque-director}
|
8
|
-
s.version = "2.2.
|
8
|
+
s.version = "2.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Nolan Frausto}]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-10-13}
|
13
13
|
s.description = %q{resque plugin for automatically scaling workers based on the amount of time it takes a job to go through the queue and/or the length of the queue }
|
14
14
|
s.email = %q{nrfrausto@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,8 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
".document",
|
21
20
|
"Gemfile",
|
21
|
+
"HISTORY.md",
|
22
22
|
"LICENSE.txt",
|
23
23
|
"README.rdoc",
|
24
24
|
"Rakefile",
|
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
s.homepage = %q{http://github.com/frausto/resque-director}
|
43
43
|
s.licenses = [%q{MIT}]
|
44
44
|
s.require_paths = [%q{lib}]
|
45
|
-
s.rubygems_version = %q{1.8.
|
45
|
+
s.rubygems_version = %q{1.8.6}
|
46
46
|
s.summary = %q{A resque plugin for automatically scaling workers}
|
47
47
|
|
48
48
|
if s.respond_to? :specification_version then
|
@@ -94,13 +94,13 @@ describe Resque::Plugins::Director::Scaler do
|
|
94
94
|
end
|
95
95
|
|
96
96
|
it "should scale workers down to the minimum" do
|
97
|
-
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
97
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker, @worker]
|
98
98
|
Process.should_receive(:kill).twice
|
99
99
|
subject.scale_down_to_minimum
|
100
100
|
end
|
101
101
|
|
102
102
|
it "should not scale if the workers are already at the minimum" do
|
103
|
-
Resque.should_receive(:workers).and_return [@worker]
|
103
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
104
104
|
Process.should_not_receive(:kill)
|
105
105
|
subject.scale_down_to_minimum
|
106
106
|
end
|
@@ -108,7 +108,7 @@ describe Resque::Plugins::Director::Scaler do
|
|
108
108
|
it "forces scaling by ignoring wait_time" do
|
109
109
|
Resque::Plugins::Director::Config.setup(:wait_time => 60, :min_workers => 2)
|
110
110
|
subject.scaling {}
|
111
|
-
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
111
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker, @worker]
|
112
112
|
Process.should_receive(:kill)
|
113
113
|
subject.scale_down_to_minimum
|
114
114
|
end
|
@@ -121,14 +121,14 @@ describe Resque::Plugins::Director::Scaler do
|
|
121
121
|
end
|
122
122
|
|
123
123
|
it "should scale down a single worker by default" do
|
124
|
-
Resque.should_receive(:workers).and_return [@worker, @worker]
|
124
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker]
|
125
125
|
|
126
126
|
Process.should_receive(:kill).once
|
127
127
|
subject.scale_down
|
128
128
|
end
|
129
129
|
|
130
130
|
it "should scale down multiple workers" do
|
131
|
-
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
131
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker, @worker]
|
132
132
|
pid = @worker.to_s.split(":")[1].to_i
|
133
133
|
Process.should_receive(:kill).with("QUIT", pid)
|
134
134
|
subject.scale_down(2)
|
@@ -137,13 +137,13 @@ describe Resque::Plugins::Director::Scaler do
|
|
137
137
|
it "should not scale down more than the minimum allowed workers" do
|
138
138
|
Resque::Plugins::Director::Config.setup :min_workers => 1
|
139
139
|
|
140
|
-
Resque.should_receive(:workers).and_return [@worker, @worker]
|
140
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker]
|
141
141
|
Process.should_receive(:kill).once
|
142
142
|
subject.scale_down(2)
|
143
143
|
end
|
144
144
|
|
145
145
|
it "should not throw exceptions when process throws exception" do
|
146
|
-
Resque.should_receive(:workers).and_return [@worker, @worker]
|
146
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker]
|
147
147
|
Process.should_receive(:kill).and_throw(:Exception)
|
148
148
|
lambda { subject.scale_down }.should_not raise_error
|
149
149
|
end
|
@@ -152,7 +152,7 @@ describe Resque::Plugins::Director::Scaler do
|
|
152
152
|
worker2 = Resque::Worker.new(:not_test)
|
153
153
|
@worker.stub(:to_s => "host:1:test")
|
154
154
|
worker2.stub(:to_s => "host:2:test")
|
155
|
-
Resque.should_receive(:workers).and_return [worker2, @worker, @worker, worker2]
|
155
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [worker2, @worker, @worker, worker2]
|
156
156
|
|
157
157
|
Process.should_not_receive(:kill).with("QUIT", 2)
|
158
158
|
Process.should_receive(:kill).with("QUIT", 1)
|
@@ -168,51 +168,46 @@ describe Resque::Plugins::Director::Scaler do
|
|
168
168
|
end
|
169
169
|
|
170
170
|
it "should kill worker by sending the QUIT signal to the workers pid" do
|
171
|
-
Resque.should_receive(:workers).and_return [@worker]
|
172
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
171
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
173
172
|
|
174
173
|
Process.should_receive(:kill).with("QUIT", @pid)
|
175
|
-
subject.send(:stop,
|
174
|
+
subject.send(:stop, 1)
|
176
175
|
end
|
177
176
|
|
178
177
|
it "should use the stop block to stop a worker if set" do
|
179
178
|
test_block = lambda {|queue| }
|
180
179
|
Resque::Plugins::Director::Config.setup :stop_override => test_block, :min_workers => 0
|
181
180
|
|
182
|
-
Resque.should_receive(:workers).and_return [@worker]
|
183
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
181
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
184
182
|
|
185
183
|
test_block.should_receive(:call).with("test")
|
186
184
|
Process.should_not_receive(:kill)
|
187
|
-
subject.send(:stop,
|
185
|
+
subject.send(:stop, 1)
|
188
186
|
end
|
189
187
|
|
190
188
|
it "does not stop workers already set to be shutdown" do
|
191
189
|
@worker.should_receive(:shutdown?).and_return(true)
|
192
|
-
Resque.should_receive(:workers).and_return [@worker]
|
193
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
190
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
194
191
|
|
195
192
|
Process.should_not_receive(:kill).with("QUIT", @pid)
|
196
|
-
subject.send(:stop,
|
193
|
+
subject.send(:stop, 1)
|
197
194
|
end
|
198
195
|
|
199
196
|
it "does not kill worker processes on different machines" do
|
200
197
|
@worker.stub!(:hostname => "different_machine")
|
201
|
-
Resque.should_receive(:workers).and_return [@worker]
|
202
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
198
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
203
199
|
|
204
200
|
Process.should_not_receive(:kill).with("QUIT", @pid)
|
205
|
-
subject.send(:stop,
|
201
|
+
subject.send(:stop, 1)
|
206
202
|
end
|
207
203
|
|
208
204
|
it "stops workers on the same host if possible" do
|
209
205
|
worker2 = Resque::Worker.new(:test)
|
210
206
|
worker2.stub!(:hostname => "different_machine")
|
211
|
-
Resque.should_receive(:workers).and_return [worker2, @worker]
|
212
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
207
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [worker2, @worker]
|
213
208
|
|
214
209
|
Process.should_receive(:kill).with("QUIT", @pid)
|
215
|
-
subject.send(:stop,
|
210
|
+
subject.send(:stop, 1)
|
216
211
|
end
|
217
212
|
|
218
213
|
it "ignores hostname if using custom stop script" do
|
@@ -220,12 +215,11 @@ describe Resque::Plugins::Director::Scaler do
|
|
220
215
|
Resque::Plugins::Director::Config.setup :stop_override => test_block, :min_workers => 0
|
221
216
|
|
222
217
|
@worker.stub!(:hostname => "different_machine")
|
223
|
-
Resque.should_receive(:workers).and_return [@worker]
|
224
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
218
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker]
|
225
219
|
|
226
220
|
test_block.should_receive(:call).with("test")
|
227
221
|
Process.should_not_receive(:kill)
|
228
|
-
subject.send(:stop,
|
222
|
+
subject.send(:stop, 1)
|
229
223
|
end
|
230
224
|
end
|
231
225
|
|
@@ -264,7 +258,7 @@ describe Resque::Plugins::Director::Scaler do
|
|
264
258
|
Time.stub(:now => @now)
|
265
259
|
Resque::Plugins::Director::Config.setup :max_workers => 1, :wait_time => 60
|
266
260
|
workers = 2.times.map { Resque::Worker.new(:test) }
|
267
|
-
Resque.should_receive(:workers).and_return(workers)
|
261
|
+
Resque.should_receive(:workers).any_number_of_times.and_return(workers)
|
268
262
|
subject.should_receive(:stop)
|
269
263
|
|
270
264
|
subject.scale_within_requirements
|
@@ -293,16 +287,16 @@ describe Resque::Plugins::Director::Scaler do
|
|
293
287
|
it "should scale down the max number of workers if more than max" do
|
294
288
|
Resque::Plugins::Director::Config.setup :max_workers => 1
|
295
289
|
workers = 2.times.map { Resque::Worker.new(:test) }
|
296
|
-
Resque.should_receive(:workers).and_return(workers)
|
290
|
+
Resque.should_receive(:workers).any_number_of_times.and_return(workers)
|
297
291
|
|
298
|
-
subject.should_receive(:stop).with(
|
292
|
+
subject.should_receive(:stop).with(1)
|
299
293
|
subject.scale_within_requirements
|
300
294
|
end
|
301
295
|
|
302
296
|
it "should not scale down if max_workers is zero" do
|
303
297
|
Resque::Plugins::Director::Config.setup :max_workers => 0
|
304
298
|
workers = 1.times.map { Resque::Worker.new(:test) }
|
305
|
-
Resque.should_receive(:workers).and_return(workers)
|
299
|
+
Resque.should_receive(:workers).any_number_of_times.and_return(workers)
|
306
300
|
|
307
301
|
subject.should_not_receive(:stop)
|
308
302
|
subject.scale_within_requirements
|
@@ -8,22 +8,50 @@ describe Resque::Plugins::Director::WorkerTracker do
|
|
8
8
|
@worker = Resque::Worker.new(:test)
|
9
9
|
end
|
10
10
|
|
11
|
-
describe "#
|
12
|
-
before do
|
13
|
-
Resque::Plugins::Director::Config.queue = "worker_test"
|
14
|
-
end
|
15
|
-
|
11
|
+
describe "#current_workers" do
|
16
12
|
it"should return the workers for the queue" do
|
13
|
+
Resque::Plugins::Director::Config.queue = "worker_test"
|
17
14
|
Resque::Worker.new(:other).register_worker
|
18
15
|
expected_worker = Resque::Worker.new(:worker_test)
|
19
16
|
expected_worker.register_worker
|
20
17
|
|
21
|
-
subject.
|
18
|
+
subject.send(:current_workers).should == [expected_worker]
|
22
19
|
end
|
23
20
|
|
24
21
|
it "should not return workers working on multiple queues" do
|
25
22
|
Resque::Worker.new(:worker_test, :other).register_worker
|
26
|
-
subject.
|
23
|
+
subject.send(:current_workers).should be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets the workers from the queue" do
|
27
|
+
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
28
|
+
subject.send(:current_workers).should == [@worker, @worker, @worker]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "does not set workers from different queues" do
|
32
|
+
other_worker = Resque::Worker.new(:other)
|
33
|
+
Resque.should_receive(:workers).and_return [@worker, other_worker, @worker]
|
34
|
+
subject.send(:current_workers).should == [@worker, @worker]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not set workers that are scheduled for shutdow" do
|
38
|
+
shutdown_worker = Resque::Worker.new(:test)
|
39
|
+
shutdown_worker.shutdown
|
40
|
+
Resque.should_receive(:workers).and_return [shutdown_worker, @worker, @worker]
|
41
|
+
subject.send(:current_workers).should == [@worker, @worker]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "does not set workers that have the queue included with others" do
|
45
|
+
other_worker = Resque::Worker.new(:other, :test)
|
46
|
+
Resque.should_receive(:workers).and_return [@worker, other_worker, @worker]
|
47
|
+
subject.send(:current_workers).should == [@worker, @worker]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "finds workers working on multiple queues if specified" do
|
51
|
+
other_worker = Resque::Worker.new(:other, :test)
|
52
|
+
Resque::Plugins::Director::Config.queue = [:other,:test]
|
53
|
+
Resque.should_receive(:workers).and_return [@worker, other_worker]
|
54
|
+
subject.send(:current_workers).should == [other_worker]
|
27
55
|
end
|
28
56
|
end
|
29
57
|
|
@@ -31,41 +59,41 @@ describe Resque::Plugins::Director::WorkerTracker do
|
|
31
59
|
it "should limit the workers to be removed to not go below minimum allowed workers" do
|
32
60
|
Resque.should_receive(:workers).and_return [@worker, @worker]
|
33
61
|
Resque::Plugins::Director::Config.setup :min_workers => 1
|
34
|
-
subject.
|
62
|
+
subject.total_to_remove(2).should == 1
|
35
63
|
end
|
36
64
|
|
37
65
|
it "always keeps at least one worker" do
|
38
66
|
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
39
67
|
Resque::Plugins::Director::Config.setup :min_workers => 0
|
40
|
-
subject.
|
68
|
+
subject.total_to_remove(2).should == 2
|
41
69
|
end
|
42
70
|
|
43
71
|
it "should return zero if there is only one worker working" do
|
44
72
|
Resque.should_receive(:workers).and_return [@worker]
|
45
73
|
Resque::Plugins::Director::Config.setup :min_workers => 0
|
46
|
-
subject.
|
74
|
+
subject.total_to_remove(1).should == 0
|
47
75
|
end
|
48
76
|
end
|
49
77
|
|
50
78
|
|
51
79
|
describe "#total_to_add" do
|
52
80
|
before do
|
53
|
-
Resque.
|
81
|
+
Resque.stub(:workers).and_return [@worker, @worker]
|
54
82
|
end
|
55
83
|
|
56
84
|
it "should limit the workers to be removed to not go below minimum allowed workers" do
|
57
85
|
Resque::Plugins::Director::Config.setup :max_workers => 3
|
58
|
-
subject.
|
86
|
+
subject.total_to_add(2).should == 1
|
59
87
|
end
|
60
88
|
|
61
89
|
it "should allow the workers to be removed if it stays above the minimum" do
|
62
90
|
Resque::Plugins::Director::Config.setup :max_workers => 4
|
63
|
-
subject.
|
91
|
+
subject.total_to_add(2).should == 2
|
64
92
|
end
|
65
93
|
|
66
94
|
it "should not limit workers added if max_workers is zero" do
|
67
95
|
Resque::Plugins::Director::Config.setup :max_workers => 0
|
68
|
-
subject.
|
96
|
+
subject.total_to_add(200).should == 200
|
69
97
|
end
|
70
98
|
end
|
71
99
|
|
@@ -73,25 +101,25 @@ describe Resque::Plugins::Director::WorkerTracker do
|
|
73
101
|
it "should return the number of workers needed to meet the minimum requirement" do
|
74
102
|
Resque.should_receive(:workers).and_return [@worker, @worker]
|
75
103
|
Resque::Plugins::Director::Config.setup :min_workers => 4
|
76
|
-
subject.
|
104
|
+
subject.total_for_requirements.should == 2
|
77
105
|
end
|
78
106
|
|
79
107
|
it "should return the number of workers needed to meet the maximum requirement" do
|
80
|
-
Resque.should_receive(:workers).and_return [@worker, @worker]
|
108
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker]
|
81
109
|
Resque::Plugins::Director::Config.setup :max_workers => 1
|
82
|
-
subject.
|
110
|
+
subject.total_for_requirements.should == -1
|
83
111
|
end
|
84
112
|
|
85
113
|
it "should return 1 no workers are running and the minimum is zero" do
|
86
114
|
Resque.should_receive(:workers).and_return []
|
87
115
|
Resque::Plugins::Director::Config.setup :min_workers => 0
|
88
|
-
subject.
|
116
|
+
subject.total_for_requirements.should == 1
|
89
117
|
end
|
90
118
|
|
91
119
|
it "should return 0 if number of workers is within requirements" do
|
92
|
-
Resque.should_receive(:workers).and_return [@worker, @worker]
|
120
|
+
Resque.should_receive(:workers).any_number_of_times.and_return [@worker, @worker]
|
93
121
|
Resque::Plugins::Director::Config.setup :min_workers => 1, :max_workers => 3
|
94
|
-
subject.
|
122
|
+
subject.total_for_requirements.should == 0
|
95
123
|
end
|
96
124
|
end
|
97
125
|
|
@@ -99,19 +127,19 @@ describe Resque::Plugins::Director::WorkerTracker do
|
|
99
127
|
it "should return the number to scale down to go to the minimum" do
|
100
128
|
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
101
129
|
Resque::Plugins::Director::Config.setup :min_workers => 2
|
102
|
-
subject.
|
130
|
+
subject.total_to_go_to_minimum.should == 1
|
103
131
|
end
|
104
132
|
|
105
133
|
it "should return zero if already at the minimum" do
|
106
134
|
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
107
135
|
Resque::Plugins::Director::Config.setup :min_workers => 3
|
108
|
-
subject.
|
136
|
+
subject.total_to_go_to_minimum.should == 0
|
109
137
|
end
|
110
138
|
|
111
139
|
it "should return zero if below the minimum" do
|
112
140
|
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
113
141
|
Resque::Plugins::Director::Config.setup :min_workers => 4
|
114
|
-
subject.
|
142
|
+
subject.total_to_go_to_minimum.should == 0
|
115
143
|
end
|
116
144
|
end
|
117
145
|
|
@@ -121,42 +149,8 @@ describe Resque::Plugins::Director::WorkerTracker do
|
|
121
149
|
worker2 = Resque::Worker.new(:test)
|
122
150
|
pid = worker2.to_s.split(":")[1].to_i
|
123
151
|
Resque.should_receive(:workers).and_return [@worker, worker2]
|
124
|
-
tracker = Resque::Plugins::Director::WorkerTracker.new
|
125
152
|
|
126
|
-
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe "#initialize" do
|
131
|
-
it "sets the workers from the queue" do
|
132
|
-
Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
|
133
|
-
subject.new.workers.should == [@worker, @worker, @worker]
|
134
|
-
end
|
135
|
-
|
136
|
-
it "does not set workers from different queues" do
|
137
|
-
other_worker = Resque::Worker.new(:other)
|
138
|
-
Resque.should_receive(:workers).and_return [@worker, other_worker, @worker]
|
139
|
-
subject.new.workers.should == [@worker, @worker]
|
140
|
-
end
|
141
|
-
|
142
|
-
it "does not set workers that are scheduled for shutdow" do
|
143
|
-
shutdown_worker = Resque::Worker.new(:test)
|
144
|
-
shutdown_worker.shutdown
|
145
|
-
Resque.should_receive(:workers).and_return [shutdown_worker, @worker, @worker]
|
146
|
-
subject.new.workers.should == [@worker, @worker]
|
147
|
-
end
|
148
|
-
|
149
|
-
it "does not set workers that have the queue included with others" do
|
150
|
-
other_worker = Resque::Worker.new(:other, :test)
|
151
|
-
Resque.should_receive(:workers).and_return [@worker, other_worker, @worker]
|
152
|
-
subject.new.workers.should == [@worker, @worker]
|
153
|
-
end
|
154
|
-
|
155
|
-
it "finds workers working on multiple queues if specified" do
|
156
|
-
other_worker = Resque::Worker.new(:other, :test)
|
157
|
-
Resque::Plugins::Director::Config.queue = [:other,:test]
|
158
|
-
Resque.should_receive(:workers).and_return [@worker, other_worker]
|
159
|
-
subject.new.workers.should == [other_worker]
|
153
|
+
subject.valid_worker_pids.should == [pid]
|
160
154
|
end
|
161
155
|
end
|
162
156
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-director
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 2.2.
|
9
|
+
- 3
|
10
|
+
version: 2.2.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Nolan Frausto
|
@@ -15,9 +15,10 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-10-13 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
+
type: :runtime
|
21
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
22
23
|
none: false
|
23
24
|
requirements:
|
@@ -31,8 +32,8 @@ dependencies:
|
|
31
32
|
version_requirements: *id001
|
32
33
|
name: resque
|
33
34
|
prerelease: false
|
34
|
-
type: :runtime
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
+
type: :development
|
36
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
38
|
none: false
|
38
39
|
requirements:
|
@@ -47,8 +48,8 @@ dependencies:
|
|
47
48
|
version_requirements: *id002
|
48
49
|
name: rspec
|
49
50
|
prerelease: false
|
50
|
-
type: :development
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
+
type: :development
|
52
53
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
54
|
none: false
|
54
55
|
requirements:
|
@@ -63,8 +64,8 @@ dependencies:
|
|
63
64
|
version_requirements: *id003
|
64
65
|
name: bundler
|
65
66
|
prerelease: false
|
66
|
-
type: :development
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
+
type: :development
|
68
69
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
70
|
none: false
|
70
71
|
requirements:
|
@@ -79,8 +80,8 @@ dependencies:
|
|
79
80
|
version_requirements: *id004
|
80
81
|
name: jeweler
|
81
82
|
prerelease: false
|
82
|
-
type: :development
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
+
type: :development
|
84
85
|
requirement: &id005 !ruby/object:Gem::Requirement
|
85
86
|
none: false
|
86
87
|
requirements:
|
@@ -93,8 +94,8 @@ dependencies:
|
|
93
94
|
version_requirements: *id005
|
94
95
|
name: rcov
|
95
96
|
prerelease: false
|
96
|
-
type: :development
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
+
type: :development
|
98
99
|
requirement: &id006 !ruby/object:Gem::Requirement
|
99
100
|
none: false
|
100
101
|
requirements:
|
@@ -109,8 +110,8 @@ dependencies:
|
|
109
110
|
version_requirements: *id006
|
110
111
|
name: yajl-ruby
|
111
112
|
prerelease: false
|
112
|
-
type: :development
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
|
+
type: :development
|
114
115
|
requirement: &id007 !ruby/object:Gem::Requirement
|
115
116
|
none: false
|
116
117
|
requirements:
|
@@ -125,7 +126,6 @@ dependencies:
|
|
125
126
|
version_requirements: *id007
|
126
127
|
name: json
|
127
128
|
prerelease: false
|
128
|
-
type: :development
|
129
129
|
description: "resque plugin for automatically scaling workers based on the amount of time it takes a job to go through the queue and/or the length of the queue "
|
130
130
|
email: nrfrausto@gmail.com
|
131
131
|
executables: []
|
@@ -136,8 +136,8 @@ extra_rdoc_files:
|
|
136
136
|
- LICENSE.txt
|
137
137
|
- README.rdoc
|
138
138
|
files:
|
139
|
-
- .document
|
140
139
|
- Gemfile
|
140
|
+
- HISTORY.md
|
141
141
|
- LICENSE.txt
|
142
142
|
- README.rdoc
|
143
143
|
- Rakefile
|
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
186
|
requirements: []
|
187
187
|
|
188
188
|
rubyforge_project:
|
189
|
-
rubygems_version: 1.8.
|
189
|
+
rubygems_version: 1.8.6
|
190
190
|
signing_key:
|
191
191
|
specification_version: 3
|
192
192
|
summary: A resque plugin for automatically scaling workers
|