heroku_resque_autoscaler 0.0.1
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 +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +120 -0
- data/Rakefile +2 -0
- data/heroku_resque_autoscaler.gemspec +25 -0
- data/lib/heroku_resque_autoscaler/configuration.rb +52 -0
- data/lib/heroku_resque_autoscaler/exceptions.rb +3 -0
- data/lib/heroku_resque_autoscaler/scaler.rb +78 -0
- data/lib/heroku_resque_autoscaler/version.rb +3 -0
- data/lib/heroku_resque_autoscaler.rb +31 -0
- data/spec/lib/heroku_resque_autoscaler/configuration_spec.rb +42 -0
- data/spec/lib/heroku_resque_autoscaler/scaler_spec.rb +113 -0
- data/spec/lib/heroku_resque_autoscaler_spec.rb +28 -0
- data/spec/spec_helper.rb +3 -0
- metadata +167 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 G5
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Heroku Resque Autoscaler
|
2
|
+
|
3
|
+
Uses Resque Job Hooks and the Heroku API gem to autoscale Heroku Resque workers
|
4
|
+
|
5
|
+
Inspired by [@darkhelmet](https://github.com/darkhelmet)'s
|
6
|
+
[Auto-scale Your Resque Workers On Heroku](http://verboselogging.com/2010/07/30/auto-scale-your-resque-workers-on-heroku)
|
7
|
+
|
8
|
+
|
9
|
+
## Current Version
|
10
|
+
|
11
|
+
0.0.1
|
12
|
+
|
13
|
+
|
14
|
+
## Requirements
|
15
|
+
|
16
|
+
* ["heroku_api", "~> 0.3.5"](http://rubygems.org/gems/heroku-api)
|
17
|
+
* ["resque", "~> 1.23.0"](http://rubygems.org/gems/resque)
|
18
|
+
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
### Gemfile
|
23
|
+
|
24
|
+
Add this line to your application's Gemfile:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
gem 'heroku_resque_autoscaler'
|
28
|
+
```
|
29
|
+
|
30
|
+
### Manual
|
31
|
+
|
32
|
+
Or install it yourself:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
gem install heroku_resque_autoscaler
|
36
|
+
```
|
37
|
+
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
Set defaults in an initializer, defaults are shown:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
HerokuResqueAutoscaler.configure do |config|
|
45
|
+
config.heroku_api_key = ENV["HEROKU_API_KEY"]
|
46
|
+
config.heroku_app_name = ENV["HEROKU_APP_NAME"]
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Export you environment variables wherever you do that:
|
51
|
+
|
52
|
+
```bash
|
53
|
+
export HEROKU_API_KEY=heroku_api_key
|
54
|
+
export HEROKU_APP_NAME=heroku_app_name
|
55
|
+
```
|
56
|
+
|
57
|
+
Your Resque workers should extend HerokuResqueAutoscaler:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class AutoscaledJob
|
61
|
+
extend HerokuResqueAutoscaler
|
62
|
+
|
63
|
+
def self.perform
|
64
|
+
# Do something
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
|
70
|
+
## Authors
|
71
|
+
|
72
|
+
* Jessica Lynn Suttles / [@jlsuttles](https://github.com/jlsuttles)
|
73
|
+
* Bookis Smuin / [@bookis](https://github.com/bookis)
|
74
|
+
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
1. Fork it
|
79
|
+
2. Get it running
|
80
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
81
|
+
4. Write your code and **specs**
|
82
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
84
|
+
7. Create new Pull Request
|
85
|
+
|
86
|
+
If you find bugs, have feature requests or questions, please
|
87
|
+
[file an issue](https://github.com/G5/heroku_resque_autoscaler/issues).
|
88
|
+
|
89
|
+
|
90
|
+
## Specs
|
91
|
+
|
92
|
+
```bash
|
93
|
+
rspec spec
|
94
|
+
```
|
95
|
+
|
96
|
+
|
97
|
+
## License
|
98
|
+
|
99
|
+
Copyright (c) 2012 G5
|
100
|
+
|
101
|
+
MIT License
|
102
|
+
|
103
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
104
|
+
a copy of this software and associated documentation files (the
|
105
|
+
"Software"), to deal in the Software without restriction, including
|
106
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
107
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
108
|
+
permit persons to whom the Software is furnished to do so, subject to
|
109
|
+
the following conditions:
|
110
|
+
|
111
|
+
The above copyright notice and this permission notice shall be
|
112
|
+
included in all copies or substantial portions of the Software.
|
113
|
+
|
114
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
115
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
116
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
117
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
118
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
119
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
120
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/heroku_resque_autoscaler/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "heroku_resque_autoscaler"
|
6
|
+
gem.version = HerokuResqueAutoscaler::VERSION
|
7
|
+
gem.authors = ["Jessica Lynn Suttles"]
|
8
|
+
gem.email = ["jlsuttles@gmail.com"]
|
9
|
+
gem.description = %q{Uses Resque Job Hooks and the Heroku API gem to autoscale Heroku Resque workers}
|
10
|
+
gem.summary = %q{Uses Resque Job Hooks and the Heroku API gem to autoscale Heroku Resque workers}
|
11
|
+
gem.homepage = ""
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
|
18
|
+
gem.add_runtime_dependency "heroku-api", "~> 0.3.5"
|
19
|
+
gem.add_runtime_dependency "resque", "~> 1.23.0"
|
20
|
+
|
21
|
+
gem.add_development_dependency "rspec", "~> 2.11.0"
|
22
|
+
gem.add_development_dependency "guard-rspec", "~> 2.1.0"
|
23
|
+
gem.add_development_dependency "rb-fsevent", "~> 0.9.2"
|
24
|
+
gem.add_development_dependency "debugger", "~> 1.2.1"
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module HerokuResqueAutoscaler
|
2
|
+
class Configuration
|
3
|
+
OPTIONS = {
|
4
|
+
heroku_api_key: ENV["HEROKU_API_KEY"],
|
5
|
+
heroku_app_name: ENV["HEROKU_APP_NAME"],
|
6
|
+
}
|
7
|
+
|
8
|
+
# Defines accessors for all OPTIONS
|
9
|
+
OPTIONS.each_pair do |key, value|
|
10
|
+
attr_accessor key
|
11
|
+
end
|
12
|
+
|
13
|
+
# Initializes defaults to be the environment varibales of the same names
|
14
|
+
def initialize
|
15
|
+
OPTIONS.each_pair do |key, value|
|
16
|
+
self.send("#{key}=", value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Allows config options to be read like a hash
|
21
|
+
#
|
22
|
+
# @param [Symbol] option Key for a given attribute
|
23
|
+
def [](option)
|
24
|
+
send(option)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a hash of all configurable options
|
28
|
+
def to_hash
|
29
|
+
OPTIONS.inject({}) do |hash, option|
|
30
|
+
key = option.first
|
31
|
+
hash[key] = self.send(key)
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns a hash of all configurable options merged with +hash+
|
37
|
+
#
|
38
|
+
# @param [Hash] hash A set of configuration options that will take
|
39
|
+
# precedence over the defaults
|
40
|
+
def merge(hash)
|
41
|
+
to_hash.merge(hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_presence(options)
|
45
|
+
OPTIONS.each_pair do |key, value|
|
46
|
+
if options[key].nil?
|
47
|
+
raise HerokuResqueAutoscaler::ConfigurationException, "#{key} is missing"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "heroku-api"
|
2
|
+
require "resque"
|
3
|
+
|
4
|
+
module HerokuResqueAutoscaler
|
5
|
+
module Scaler
|
6
|
+
class << self
|
7
|
+
# TODO: use HerokuResqueAutoscaler.configuration for api_key
|
8
|
+
@@heroku = Heroku::API.new(api_key: ENV["HEROKU_API_KEY"])
|
9
|
+
|
10
|
+
def api_key
|
11
|
+
HerokuResqueAutoscaler.configuration["heroku_api_key"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def app_name
|
15
|
+
HerokuResqueAutoscaler.configuration["heroku_app_name"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def workers
|
19
|
+
@@heroku.get_ps(app_name).body.keep_if do |ps|
|
20
|
+
ps["process"] =~ /worker/
|
21
|
+
end.length.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def workers=(qty)
|
25
|
+
@@heroku.post_ps_scale(app_name, :worker, qty)
|
26
|
+
end
|
27
|
+
|
28
|
+
def job_count
|
29
|
+
Resque.info[:pending].to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
def working_job_count
|
33
|
+
Resque.info[:working].to_i
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def after_perform_scale_down(*args)
|
39
|
+
# Scale everything down if we have no pending jobs and one working job (this one)
|
40
|
+
Scaler.workers = 0 if Scaler.job_count.zero? && Scaler.working_job_count == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
def num_desired_heroku_workers(*args)
|
44
|
+
[
|
45
|
+
{
|
46
|
+
:workers => 1, # This many workers
|
47
|
+
:job_count => 1 # For this many jobs or more, until the next level
|
48
|
+
},
|
49
|
+
{
|
50
|
+
:workers => 2,
|
51
|
+
:job_count => 15
|
52
|
+
},
|
53
|
+
{
|
54
|
+
:workers => 3,
|
55
|
+
:job_count => 25
|
56
|
+
},
|
57
|
+
{
|
58
|
+
:workers => 4,
|
59
|
+
:job_count => 40
|
60
|
+
},
|
61
|
+
{
|
62
|
+
:workers => 5,
|
63
|
+
:job_count => 60
|
64
|
+
}
|
65
|
+
].reverse_each do |scale_info|
|
66
|
+
if Scaler.job_count >= scale_info[:job_count]
|
67
|
+
return scale_info[:workers]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def after_enqueue_scale_up(*args)
|
73
|
+
desired_workers = num_desired_heroku_workers
|
74
|
+
if Scaler.workers < desired_workers
|
75
|
+
Scaler.workers = desired_workers
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "heroku_resque_autoscaler/version"
|
2
|
+
require "heroku_resque_autoscaler/configuration"
|
3
|
+
require "heroku_resque_autoscaler/scaler"
|
4
|
+
|
5
|
+
module HerokuResqueAutoscaler
|
6
|
+
class << self
|
7
|
+
# A HerokuResqueAutoscaler configuration object. Must act like a hash and
|
8
|
+
# return sensible values for all HerokuResqueAutoscaler configuration options.
|
9
|
+
#
|
10
|
+
# @see HerokuResqueAutoscaler::Configuration.
|
11
|
+
attr_writer :configuration
|
12
|
+
|
13
|
+
# The configuration object.
|
14
|
+
#
|
15
|
+
# @see HerokuResqueAutoscaler.configure
|
16
|
+
def configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Call this method to modify defaults in your initializers.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# HerokuResqueAutoscaler.configure do |config|
|
24
|
+
# config.heroku_api_key = ENV["HEROKU_API_KEY"]
|
25
|
+
# config.heroku_app_name = ENV["HEROKU_APP_NAME"]
|
26
|
+
# end
|
27
|
+
def configure
|
28
|
+
yield(configuration)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'heroku_resque_autoscaler'
|
3
|
+
require 'heroku_resque_autoscaler/configuration'
|
4
|
+
|
5
|
+
describe HerokuResqueAutoscaler::Configuration do
|
6
|
+
it { should respond_to :"[]" }
|
7
|
+
it { should respond_to :to_hash }
|
8
|
+
it { should respond_to :merge }
|
9
|
+
|
10
|
+
it "provides default values" do
|
11
|
+
assert_config_default :heroku_api_key, ENV["HEROKU_API_KEY"]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "allows values to be overwritten" do
|
15
|
+
assert_config_overridable :heroku_api_key
|
16
|
+
end
|
17
|
+
|
18
|
+
it "acts like a hash" do
|
19
|
+
config = HerokuResqueAutoscaler::Configuration.new
|
20
|
+
hash = config.to_hash
|
21
|
+
HerokuResqueAutoscaler::Configuration::OPTIONS.each_pair do |key, value|
|
22
|
+
config[key].should eq(hash[key])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is mergable" do
|
27
|
+
config = HerokuResqueAutoscaler::Configuration.new
|
28
|
+
hash = config.to_hash
|
29
|
+
config.merge(:key => 'value').should eq(hash.merge(:key => 'value'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_config_default(option, default_value, config = nil)
|
33
|
+
config ||= HerokuResqueAutoscaler::Configuration.new
|
34
|
+
config.send(option).should eq(default_value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_config_overridable(option, value = 'a value')
|
38
|
+
config = HerokuResqueAutoscaler::Configuration.new
|
39
|
+
config.send(:"#{option}=", value)
|
40
|
+
config.send(option).should eq(value)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'heroku_resque_autoscaler'
|
3
|
+
require 'heroku_resque_autoscaler/scaler'
|
4
|
+
|
5
|
+
require "spec_helper"
|
6
|
+
|
7
|
+
class HerokuResqueAutoscalerTestClass
|
8
|
+
extend HerokuResqueAutoscaler
|
9
|
+
end
|
10
|
+
|
11
|
+
describe HerokuResqueAutoscaler do
|
12
|
+
before :each do
|
13
|
+
@heroku = mock(Heroku::API)
|
14
|
+
HerokuResqueAutoscaler::Scaler.class_variable_set(:@@heroku, @heroku)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:heroku_app) {ENV['HEROKU_APP_NAME']}
|
18
|
+
|
19
|
+
context "#workers" do
|
20
|
+
it "returns the number of workers from the Heroku application" do
|
21
|
+
@heroku.should_receive(:get_ps).with(heroku_app).and_return([
|
22
|
+
{"process" => "web.1"},
|
23
|
+
{"process" => "worker.1"},
|
24
|
+
{"process" => "worker.1"},
|
25
|
+
])
|
26
|
+
HerokuResqueAutoscaler::Scaler.workers.should == 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "#workers=" do
|
31
|
+
it "sets the number of workers on Heroku to some quantity" do
|
32
|
+
quantity = 10
|
33
|
+
@heroku.should_receive(:post_ps_scale).with(heroku_app, :worker, quantity)
|
34
|
+
HerokuResqueAutoscaler::Scaler.workers = quantity
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#job_count" do
|
39
|
+
it "returns the Resque job count" do
|
40
|
+
num_pending = 10
|
41
|
+
Resque.should_receive(:info).and_return({:pending => num_pending})
|
42
|
+
HerokuResqueAutoscaler::Scaler.job_count.should == num_pending
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "#num_desired_heroku_workers" do
|
47
|
+
it "returns the number of workers we should have (1 worker per x jobs)" do
|
48
|
+
num_jobs = 100
|
49
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(num_jobs)
|
50
|
+
HerokuResqueAutoscalerTestClass.num_desired_heroku_workers.should == 5
|
51
|
+
|
52
|
+
num_jobs = 38
|
53
|
+
HerokuResqueAutoscaler::Scaler.unstub(:job_count)
|
54
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(num_jobs)
|
55
|
+
HerokuResqueAutoscalerTestClass.num_desired_heroku_workers.should == 3
|
56
|
+
|
57
|
+
num_jobs = 1
|
58
|
+
HerokuResqueAutoscaler::Scaler.unstub(:job_count)
|
59
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(num_jobs)
|
60
|
+
HerokuResqueAutoscalerTestClass.num_desired_heroku_workers.should == 1
|
61
|
+
|
62
|
+
num_jobs = 10000
|
63
|
+
HerokuResqueAutoscaler::Scaler.unstub(:job_count)
|
64
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(num_jobs)
|
65
|
+
HerokuResqueAutoscalerTestClass.num_desired_heroku_workers.should == 5
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "#after_perform_scale_down" do
|
70
|
+
it "scales down the workers to zero if there are no jobs pending" do
|
71
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(0)
|
72
|
+
HerokuResqueAutoscaler::Scaler.stub(:workers).and_return(1)
|
73
|
+
HerokuResqueAutoscaler::Scaler.stub(:working_job_count).and_return(1)
|
74
|
+
HerokuResqueAutoscaler::Scaler.should_receive(:workers=).with(0)
|
75
|
+
HerokuResqueAutoscalerTestClass.after_perform_scale_down
|
76
|
+
end
|
77
|
+
|
78
|
+
it "does not scale down the workers if there are jobs pending" do
|
79
|
+
HerokuResqueAutoscaler::Scaler.stub(:job_count).and_return(1)
|
80
|
+
HerokuResqueAutoscaler::Scaler.should_not_receive(:workers=)
|
81
|
+
HerokuResqueAutoscalerTestClass.after_perform_scale_down
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "#after_enqueue_scale_up" do
|
86
|
+
it "ups the amount of workers if there are not enough" do
|
87
|
+
num_workers = 5
|
88
|
+
num_desired_workers = 6
|
89
|
+
HerokuResqueAutoscaler::Scaler.stub(:workers).and_return(num_workers)
|
90
|
+
HerokuResqueAutoscalerTestClass.stub(:num_desired_heroku_workers).and_return(num_desired_workers)
|
91
|
+
HerokuResqueAutoscaler::Scaler.should_receive(:workers=).with(num_desired_workers)
|
92
|
+
HerokuResqueAutoscalerTestClass.after_enqueue_scale_up
|
93
|
+
end
|
94
|
+
|
95
|
+
it "does not change the amount of workers if there more workers than needed" do
|
96
|
+
num_workers = 6
|
97
|
+
num_desired_workers = 5
|
98
|
+
HerokuResqueAutoscaler::Scaler.stub(:workers).and_return(num_workers)
|
99
|
+
HerokuResqueAutoscalerTestClass.stub(:num_desired_heroku_workers).and_return(num_desired_workers)
|
100
|
+
HerokuResqueAutoscaler::Scaler.should_not_receive(:workers=)
|
101
|
+
HerokuResqueAutoscalerTestClass.after_enqueue_scale_up
|
102
|
+
end
|
103
|
+
|
104
|
+
it "does not change the amount of workers if there are exactly the number required" do
|
105
|
+
num_workers = 6
|
106
|
+
num_desired_workers = 6
|
107
|
+
HerokuResqueAutoscaler::Scaler.stub(:workers).and_return(num_workers)
|
108
|
+
HerokuResqueAutoscalerTestClass.stub(:num_desired_heroku_workers).and_return(num_desired_workers)
|
109
|
+
HerokuResqueAutoscaler::Scaler.should_not_receive(:workers=)
|
110
|
+
HerokuResqueAutoscalerTestClass.after_enqueue_scale_up
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'heroku_resque_autoscaler'
|
3
|
+
|
4
|
+
describe HerokuResqueAutoscaler do
|
5
|
+
it { should respond_to :configuration }
|
6
|
+
it { should respond_to :configure }
|
7
|
+
|
8
|
+
describe "::configuration" do
|
9
|
+
it "should be the configuration object" do
|
10
|
+
HerokuResqueAutoscaler.configuration.should(
|
11
|
+
be_a_kind_of HerokuResqueAutoscaler::Configuration)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "give a new instance if non defined" do
|
15
|
+
HerokuResqueAutoscaler.configuration = nil
|
16
|
+
HerokuResqueAutoscaler.configuration.should(
|
17
|
+
be_a_kind_of HerokuResqueAutoscaler::Configuration)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "::configure" do
|
22
|
+
it "should yield the configuration object" do
|
23
|
+
HerokuResqueAutoscaler.configure do |config|
|
24
|
+
config.should equal(HerokuResqueAutoscaler.configuration)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: heroku_resque_autoscaler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jessica Lynn Suttles
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: heroku-api
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.5
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.5
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: resque
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.23.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.23.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.11.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.11.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: guard-rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.1.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.1.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rb-fsevent
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.9.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.9.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: debugger
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.2.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.2.1
|
110
|
+
description: Uses Resque Job Hooks and the Heroku API gem to autoscale Heroku Resque
|
111
|
+
workers
|
112
|
+
email:
|
113
|
+
- jlsuttles@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- heroku_resque_autoscaler.gemspec
|
124
|
+
- lib/heroku_resque_autoscaler.rb
|
125
|
+
- lib/heroku_resque_autoscaler/configuration.rb
|
126
|
+
- lib/heroku_resque_autoscaler/exceptions.rb
|
127
|
+
- lib/heroku_resque_autoscaler/scaler.rb
|
128
|
+
- lib/heroku_resque_autoscaler/version.rb
|
129
|
+
- spec/lib/heroku_resque_autoscaler/configuration_spec.rb
|
130
|
+
- spec/lib/heroku_resque_autoscaler/scaler_spec.rb
|
131
|
+
- spec/lib/heroku_resque_autoscaler_spec.rb
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
homepage: ''
|
134
|
+
licenses: []
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
hash: -4159626300690751562
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
segments:
|
155
|
+
- 0
|
156
|
+
hash: -4159626300690751562
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 1.8.24
|
160
|
+
signing_key:
|
161
|
+
specification_version: 3
|
162
|
+
summary: Uses Resque Job Hooks and the Heroku API gem to autoscale Heroku Resque workers
|
163
|
+
test_files:
|
164
|
+
- spec/lib/heroku_resque_autoscaler/configuration_spec.rb
|
165
|
+
- spec/lib/heroku_resque_autoscaler/scaler_spec.rb
|
166
|
+
- spec/lib/heroku_resque_autoscaler_spec.rb
|
167
|
+
- spec/spec_helper.rb
|