heroku_resque_autoscaler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in heroku_resque_autoscaler.gemspec
4
+ gemspec
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,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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,3 @@
1
+ module GithubHerokuDeployer
2
+ class ConfigurationException < StandardError; end
3
+ 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,3 @@
1
+ module HerokuResqueAutoscaler
2
+ VERSION = "0.0.1"
3
+ 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
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.color = true
3
+ end
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