resque-director 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,7 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "json"
4
- gem 'resque'
3
+ gem 'resque', "~> 1.14.0"
5
4
 
6
5
  group :development do
7
6
  gem "rspec", "~> 2.3.0"
data/README.rdoc CHANGED
@@ -6,6 +6,8 @@ Resque Director is a plugin for the Resque queueing system (http://github.com/de
6
6
 
7
7
  resque-director is mainly 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. Also useful in queues where the influx of jobs can change dramatically from time to time: enabling 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
+ resque-director does not operate on workers that serve multiple queues, and does not include those workers in any scaling calculations.
10
+
9
11
  == Usage
10
12
 
11
13
  When creating your jobs you should include (make sure to include not extend) Resque::Plugins::Director and add direction options.
@@ -33,7 +35,7 @@ For Example:
33
35
 
34
36
  <b>wait_time</b>:: the time that it will wait after adding or removing a worker before being allowed to add or remove workers again. The default is 60 seconds.
35
37
 
36
- == Worker Options
38
+ === Worker Options
37
39
 
38
40
  <b>start_override</b>:: This will run exactly what you put in the command override as a system command to start A SINGLE worker, allowing you to customize the starting of a worker fully. The system command "QUEUE=queue_name rake resque:work" is run by default, where queue_name is whatever queue the job is running.
39
41
 
@@ -53,6 +55,16 @@ For Example:
53
55
 
54
56
  A worker will be removed if the jobs in the queue fall below half of the <b>max_queue</b>, or if the time it takes for a job to be pulled off of a queue falls below half of the <b>max_time</b>. Workers will be scaled down to the minimum if there are no jobs on the queue.
55
57
 
58
+ === Logging
59
+
60
+ To add director logging you can pass a logger as an option. It will prepend all log messages with "DIRECTORS LOG:" and will log when scaling up or down a worker. It will also log when a worker wants to scale up or down but is unable to do so due to the fact that the maximum or minimum number of workers has been reached for that queue.
61
+
62
+ === Logger Options
63
+
64
+ <b>logger</b>:: This will set the logger that will be used. It takes a Logger from the Ruby Standard Library. If this is not set the director will not write to any logs.
65
+
66
+ <b>log_level</b>:: This sets the level to log at as a symbol. The default level is :warn.
67
+
56
68
  === Special Cases
57
69
 
58
70
  * If a max_worker is less than min_worker then the default for max_worker will be used (there will be no maximum).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.1.0
@@ -13,7 +13,9 @@ module Resque
13
13
  :max_queue => 0,
14
14
  :wait_time => 60,
15
15
  :start_override => nil,
16
- :stop_override => nil
16
+ :stop_override => nil,
17
+ :logger => nil,
18
+ :log_level => :warn
17
19
  }
18
20
 
19
21
  def reset!
@@ -22,6 +24,10 @@ module Resque
22
24
  self.instance_variable_set("@#{key.to_s}", default)
23
25
  end
24
26
  end
27
+
28
+ def log(message)
29
+ @logger.send(@log_level, "DIRECTORS LOG: #{message}") if @logger
30
+ end
25
31
 
26
32
  def setup(options={})
27
33
  DEFAULT_OPTIONS.each do |key, value|
@@ -7,7 +7,7 @@ module Resque
7
7
  def scale_up(number_of_workers=1)
8
8
  number_of_workers = WorkerTracker.new.total_to_add(number_of_workers)
9
9
  scaling(number_of_workers) do
10
- number_of_workers.times { start }
10
+ start(number_of_workers)
11
11
  end
12
12
  end
13
13
 
@@ -51,18 +51,22 @@ module Resque
51
51
  time_passed >= Config.wait_time
52
52
  end
53
53
 
54
- def start
54
+ def start(number_of_workers)
55
+ Config.log("starting #{number_of_workers} workers on queue:#{Config.queue}") if number_of_workers > 0
55
56
  default_command = "QUEUE=#{Config.queue} rake resque:work &"
56
- system(Config.start_override || default_command)
57
+ number_of_workers.times { system(Config.start_override || default_command) }
57
58
  end
58
59
 
59
60
  def stop(tracker, number_of_workers)
61
+ Config.log("stopping #{number_of_workers} workers on queue:#{Config.queue}") if number_of_workers > 0
60
62
  if Config.stop_override
61
63
  number_of_workers.times { system(Config.stop_override) }
62
64
  else
63
65
  valid_workers = tracker.workers.select{|w| w.hostname == `hostname`.chomp}
64
66
  worker_pids = valid_workers[0...number_of_workers].map(&:pid)
65
- worker_pids.each {|pid| Process.kill("QUIT", pid)}
67
+ worker_pids.each do |pid|
68
+ Process.kill("QUIT", pid) rescue nil
69
+ end
66
70
  end
67
71
  end
68
72
  end
@@ -25,12 +25,16 @@ module Resque
25
25
  def total_to_add(number_to_start)
26
26
  return number_to_start if Config.max_workers <= 0
27
27
  scale_limit = Config.max_workers - @number_working
28
+ Config.log("WORKER MAX REACHED: wanted to start #{number_to_start} workers on queue:#{Config.queue}") if scale_limit <= 0
28
29
  number_to_start > scale_limit ? scale_limit : number_to_start
29
30
  end
30
31
 
31
32
  def total_to_remove(number_to_stop)
32
33
  min_workers = Config.min_workers <= 0 ? 1 : Config.min_workers
33
34
  scale_limit = @number_working - min_workers
35
+ if scale_limit <= 0 && Config.min_workers > 0
36
+ Config.log("WORKER MIN REACHED: wanted to stop #{number_to_stop} workers on queue:#{Config.queue}")
37
+ end
34
38
  number_to_stop > scale_limit ? scale_limit : number_to_stop
35
39
  end
36
40
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{resque-director}
8
- s.version = "1.0.1"
8
+ s.version = "1.1.0"
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-08-20}
12
+ s.date = %q{2011-08-23}
13
13
  s.description = %q{resque plugin for dynamically adding/removing workers to a queue}
14
14
  s.email = %q{nrfrausto@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -50,23 +50,20 @@ Gem::Specification.new do |s|
50
50
  s.specification_version = 3
51
51
 
52
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
- s.add_runtime_dependency(%q<json>, [">= 0"])
54
- s.add_runtime_dependency(%q<resque>, [">= 0"])
53
+ s.add_runtime_dependency(%q<resque>, ["~> 1.14.0"])
55
54
  s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
56
55
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
57
56
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
58
57
  s.add_development_dependency(%q<rcov>, [">= 0"])
59
58
  else
60
- s.add_dependency(%q<json>, [">= 0"])
61
- s.add_dependency(%q<resque>, [">= 0"])
59
+ s.add_dependency(%q<resque>, ["~> 1.14.0"])
62
60
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
63
61
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
64
62
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
65
63
  s.add_dependency(%q<rcov>, [">= 0"])
66
64
  end
67
65
  else
68
- s.add_dependency(%q<json>, [">= 0"])
69
- s.add_dependency(%q<resque>, [">= 0"])
66
+ s.add_dependency(%q<resque>, ["~> 1.14.0"])
70
67
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
71
68
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
72
69
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -34,4 +34,20 @@ describe Resque::Plugins::Director::Config do
34
34
  subject.wait_time.should == 60
35
35
  end
36
36
  end
37
+
38
+ describe "log" do
39
+ it "logs message to a logger using given log level if specified" do
40
+ log = mock('Logger')
41
+ subject.setup(:logger => log, :log_level => :info)
42
+ log.should_receive(:info).with("DIRECTORS LOG: test message")
43
+ subject.log("test message")
44
+ end
45
+
46
+ it "defaults log level to warn" do
47
+ log = mock('Logger')
48
+ subject.setup(:logger => log)
49
+ log.should_receive(:warn).with("DIRECTORS LOG: test message")
50
+ subject.log("test message")
51
+ end
52
+ end
37
53
  end
@@ -83,17 +83,15 @@ describe Resque::Plugins::Director::Scaler do
83
83
  end
84
84
 
85
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]
86
+ Resque.should_receive(:workers).and_return [@worker, @worker]
88
87
 
89
88
  Process.should_receive(:kill).once
90
89
  subject.scale_down
91
90
  end
92
91
 
93
92
  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) }
93
+ Resque.should_receive(:workers).and_return [@worker, @worker, @worker]
94
+ Process.should_receive(:kill).with("QUIT", @worker.pid)
97
95
  subject.scale_down(2)
98
96
  end
99
97
 
@@ -105,11 +103,17 @@ describe Resque::Plugins::Director::Scaler do
105
103
  subject.scale_down(2)
106
104
  end
107
105
 
106
+ it "should not throw exceptions when process throws exception" do
107
+ Resque.should_receive(:workers).and_return [@worker, @worker]
108
+ Process.should_receive(:kill).and_throw(:Exception)
109
+ lambda { subject.scale_down }.should_not raise_error
110
+ end
111
+
108
112
  it "should not scale down workers on different queues" do
109
113
  worker2 = Resque::Worker.new(:not_test)
110
114
  @worker.stub(:pid => 1)
111
115
  worker2.stub(:pid => 2)
112
- Resque.should_receive(:workers).and_return [@worker, @worker, worker2]
116
+ Resque.should_receive(:workers).and_return [worker2, @worker, @worker, worker2]
113
117
 
114
118
  Process.should_not_receive(:kill).with("QUIT", worker2.pid)
115
119
  Process.should_receive(:kill).with("QUIT", @worker.pid)
@@ -120,7 +120,6 @@ describe Resque::Plugins::Director do
120
120
  end
121
121
 
122
122
  describe "with length and time" do
123
-
124
123
  before do
125
124
  @start_time = {:resdirecttime => (Time.now - 10).utc.to_i}
126
125
  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: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
8
  - 1
10
- version: 1.0.1
9
+ - 0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nolan Frausto
@@ -15,38 +15,26 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-20 00:00:00 Z
18
+ date: 2011-08-23 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  requirement: &id001 !ruby/object:Gem::Requirement
22
22
  none: false
23
23
  requirements:
24
- - - ">="
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
- hash: 3
26
+ hash: 47
27
27
  segments:
28
+ - 1
29
+ - 14
28
30
  - 0
29
- version: "0"
31
+ version: 1.14.0
30
32
  version_requirements: *id001
31
- name: json
32
- prerelease: false
33
- type: :runtime
34
- - !ruby/object:Gem::Dependency
35
- requirement: &id002 !ruby/object:Gem::Requirement
36
- none: false
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- hash: 3
41
- segments:
42
- - 0
43
- version: "0"
44
- version_requirements: *id002
45
33
  name: resque
46
34
  prerelease: false
47
35
  type: :runtime
48
36
  - !ruby/object:Gem::Dependency
49
- requirement: &id003 !ruby/object:Gem::Requirement
37
+ requirement: &id002 !ruby/object:Gem::Requirement
50
38
  none: false
51
39
  requirements:
52
40
  - - ~>
@@ -57,12 +45,12 @@ dependencies:
57
45
  - 3
58
46
  - 0
59
47
  version: 2.3.0
60
- version_requirements: *id003
48
+ version_requirements: *id002
61
49
  name: rspec
62
50
  prerelease: false
63
51
  type: :development
64
52
  - !ruby/object:Gem::Dependency
65
- requirement: &id004 !ruby/object:Gem::Requirement
53
+ requirement: &id003 !ruby/object:Gem::Requirement
66
54
  none: false
67
55
  requirements:
68
56
  - - ~>
@@ -73,12 +61,12 @@ dependencies:
73
61
  - 0
74
62
  - 0
75
63
  version: 1.0.0
76
- version_requirements: *id004
64
+ version_requirements: *id003
77
65
  name: bundler
78
66
  prerelease: false
79
67
  type: :development
80
68
  - !ruby/object:Gem::Dependency
81
- requirement: &id005 !ruby/object:Gem::Requirement
69
+ requirement: &id004 !ruby/object:Gem::Requirement
82
70
  none: false
83
71
  requirements:
84
72
  - - ~>
@@ -89,12 +77,12 @@ dependencies:
89
77
  - 6
90
78
  - 4
91
79
  version: 1.6.4
92
- version_requirements: *id005
80
+ version_requirements: *id004
93
81
  name: jeweler
94
82
  prerelease: false
95
83
  type: :development
96
84
  - !ruby/object:Gem::Dependency
97
- requirement: &id006 !ruby/object:Gem::Requirement
85
+ requirement: &id005 !ruby/object:Gem::Requirement
98
86
  none: false
99
87
  requirements:
100
88
  - - ">="
@@ -103,7 +91,7 @@ dependencies:
103
91
  segments:
104
92
  - 0
105
93
  version: "0"
106
- version_requirements: *id006
94
+ version_requirements: *id005
107
95
  name: rcov
108
96
  prerelease: false
109
97
  type: :development