heroku_auto_scale 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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +81 -0
- data/Rakefile +2 -0
- data/heroku_auto_scale.gemspec +32 -0
- data/lib/heroku_auto_scale.rb +52 -0
- data/lib/heroku_auto_scale/configuration.rb +21 -0
- data/lib/heroku_auto_scale/heroku_operations.rb +32 -0
- data/lib/heroku_auto_scale/manager.rb +81 -0
- data/lib/heroku_auto_scale/redis_operations.rb +26 -0
- data/lib/heroku_auto_scale/version.rb +3 -0
- data/spec/heroku_auto_scale/configuration_spec.rb +34 -0
- data/spec/heroku_auto_scale/heroku_operations_spec.rb +38 -0
- data/spec/heroku_auto_scale/manager_spec.rb +117 -0
- data/spec/spec_helper.rb +11 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49c7a5cc62bb1678668a81d5eaf42a9926c68a60
|
4
|
+
data.tar.gz: 0a785b077800bf7df5a0e84a07ffe604bf286c1a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cf0fac72297a756ef03071588309eaab6ef55240868894f3f43e1c3673bcd166bb752f1b78294dc4da16dfdf9de477fae6699a8ae53cc26d305e9600b6c7dc9e
|
7
|
+
data.tar.gz: d3e741458014a95a4d10ecd0ba11a82149e798be2a36e00a630a937a69b29634feaa5499cc33e308ceb275bb7a2ed91695479b5dcafca755f2d5086b64001b08
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 luki3k5
|
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,81 @@
|
|
1
|
+
# HerokuAutoScale
|
2
|
+
|
3
|
+
Idea of this gem is to allow for simple and queue system agnostic
|
4
|
+
scalability of background jobs on heroku.
|
5
|
+
|
6
|
+
Imagine having multimple queues of some kind, each time there are no
|
7
|
+
jobs these queues are just hanging there - wasting their time staying online.
|
8
|
+
On the other hand when there is a spike in number of scheduled jobs it would be
|
9
|
+
good to increase the number of dynos to process them faster.
|
10
|
+
|
11
|
+
This gem provides simple DSL for doing just that.
|
12
|
+
It allows to set a meaningful constrains for your dynos such as
|
13
|
+
minimum/maximum number of dynos and scaling step.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'heroku_auto_scale'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install heroku_auto_scale
|
30
|
+
|
31
|
+
In case of rails applications you may want to create new initializer
|
32
|
+
with the following content:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
|
36
|
+
include HerokuAutoScale
|
37
|
+
|
38
|
+
HerokuAutoScale.configure do |c|
|
39
|
+
c.redis_url = ENV['REDISCLOUD_URL']
|
40
|
+
c.heroku_oauth_token = ENV['HEROKU_TOKEN']
|
41
|
+
c.heroku_app_name = ENV['APP_NAME']
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
```
|
46
|
+
|
47
|
+
Make sure that you have corresponding environment variables setup.
|
48
|
+
|
49
|
+
## Usage
|
50
|
+
|
51
|
+
Below is simple example how to use this gem:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
|
55
|
+
heroku_observe do
|
56
|
+
queue_name "queue:followers_jobs"
|
57
|
+
process_name "sidekiq_followers"
|
58
|
+
|
59
|
+
max_dynos 2
|
60
|
+
min_dynos 1
|
61
|
+
scaling_step 2000
|
62
|
+
end
|
63
|
+
|
64
|
+
```
|
65
|
+
|
66
|
+
The meaning of options is:
|
67
|
+
- queue_name - the name of the queue in redis that you wish to observe
|
68
|
+
- process_name - name of the heroku process to scale
|
69
|
+
- max_dynos - maximum number of dynos you want to scale up to
|
70
|
+
- min_dynos - minimum number of dynos you want to scale down to
|
71
|
+
- scaling_step - number of jobs it take to scale your dynos
|
72
|
+
|
73
|
+
For adding timely checks I recommend using great [clockwork](https://github.com/adamwiggins/clockwork)
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it ( https://github.com/[my-github-username]/heroku_auto_scale/fork )
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'heroku_auto_scale/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "heroku_auto_scale"
|
8
|
+
spec.version = HerokuAutoScale::VERSION
|
9
|
+
spec.authors = ["luki3k5"]
|
10
|
+
spec.email = ["luki3k5@gmail.com"]
|
11
|
+
spec.summary = %q{Simple DSL for creating scaling rules for worker dynos on Heroku}
|
12
|
+
spec.description = %q{Simple DSL for creating scaling rules for worker dynos on Heroku}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'platform-api'
|
22
|
+
spec.add_dependency 'redis'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
27
|
+
spec.add_development_dependency "rspec-collection_matchers"
|
28
|
+
spec.add_development_dependency "webmock"
|
29
|
+
|
30
|
+
spec.add_development_dependency "awesome_print"
|
31
|
+
spec.add_development_dependency "pry"
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "heroku_auto_scale/version"
|
2
|
+
require "heroku_auto_scale/manager"
|
3
|
+
require "heroku_auto_scale/configuration"
|
4
|
+
|
5
|
+
module HerokuAutoScale
|
6
|
+
extend Configuration
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def included(includer)
|
10
|
+
includer.send("include", Methods)
|
11
|
+
includer.extend(Methods)
|
12
|
+
end
|
13
|
+
|
14
|
+
def manager
|
15
|
+
@manager ||= Manager.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Methods
|
20
|
+
|
21
|
+
def heroku_observe
|
22
|
+
yield
|
23
|
+
manage_queue
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_name(process_name)
|
27
|
+
HerokuAutoScale.manager.set_process_name(process_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def queue_name(queue_name)
|
31
|
+
HerokuAutoScale.manager.set_queue_name(queue_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def scaling_step(step)
|
35
|
+
HerokuAutoScale.manager.set_scaling_step(step)
|
36
|
+
end
|
37
|
+
|
38
|
+
def max_dynos(number_of_dynos)
|
39
|
+
HerokuAutoScale.manager.set_max_dynos(number_of_dynos)
|
40
|
+
end
|
41
|
+
|
42
|
+
def min_dynos(number_of_dynos)
|
43
|
+
HerokuAutoScale.manager.set_min_dynos(number_of_dynos)
|
44
|
+
end
|
45
|
+
|
46
|
+
def manage_queue
|
47
|
+
HerokuAutoScale.manager.manage_queue
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
extend Methods
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HerokuAutoScale
|
2
|
+
module Configuration
|
3
|
+
CONFIGURATION_OPTIONS = [
|
4
|
+
:redis_url,
|
5
|
+
:heroku_oauth_token,
|
6
|
+
:heroku_app_name
|
7
|
+
].freeze
|
8
|
+
|
9
|
+
attr_accessor *CONFIGURATION_OPTIONS
|
10
|
+
|
11
|
+
def configure
|
12
|
+
yield self
|
13
|
+
end
|
14
|
+
|
15
|
+
def options
|
16
|
+
CONFIGURATION_OPTIONS.inject({}) do |option, key|
|
17
|
+
option.merge!(key => send(key))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'platform-api'
|
2
|
+
|
3
|
+
module HerokuAutoScale
|
4
|
+
class HerokuOperations
|
5
|
+
attr_reader :heroku_connection, :app_name
|
6
|
+
|
7
|
+
def initialize(api_key, app_name)
|
8
|
+
@heroku_connection = PlatformAPI.connect_oauth(api_key)
|
9
|
+
@app_name = app_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute_dyno_scale(process_name, new_number_of_dynos)
|
13
|
+
if should_scale?(process_name, new_number_of_dynos)
|
14
|
+
scale_dynos(process_name, new_number_of_dynos)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def scale_dynos(process_name, new_number_of_dynos)
|
20
|
+
heroku_connection.formation.update(
|
21
|
+
app_name,
|
22
|
+
process_name,
|
23
|
+
{"quantity" => new_number_of_dynos}
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def should_scale?(process_name, new_number_of_dynos)
|
28
|
+
response = heroku_connection.formation.info(app_name, process_name)
|
29
|
+
response["quantity"] != new_number_of_dynos
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'heroku_auto_scale/redis_operations'
|
2
|
+
require 'heroku_auto_scale'
|
3
|
+
require 'heroku_auto_scale/configuration'
|
4
|
+
require 'heroku_auto_scale/heroku_operations'
|
5
|
+
|
6
|
+
module HerokuAutoScale
|
7
|
+
class Manager
|
8
|
+
MNGR_ATTRIBUTES = [
|
9
|
+
:process_name,
|
10
|
+
:queue_name,
|
11
|
+
:redis_operations,
|
12
|
+
:heroku_operations,
|
13
|
+
:min_dynos,
|
14
|
+
:max_dynos,
|
15
|
+
:scaling_step
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
attr_accessor *HerokuAutoScale::Configuration::CONFIGURATION_OPTIONS
|
19
|
+
attr_accessor *MNGR_ATTRIBUTES
|
20
|
+
|
21
|
+
def initialize(options={})
|
22
|
+
options = HerokuAutoScale.options.merge(options)
|
23
|
+
Configuration::CONFIGURATION_OPTIONS.each do |key|
|
24
|
+
send("#{key}=", options[key])
|
25
|
+
end
|
26
|
+
|
27
|
+
init_redis_operations
|
28
|
+
init_heroku_operations
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_number_of_jobs_inside_queue
|
32
|
+
redis_operations.check_queue_for_jobs(@queue_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_process_name(process_name)
|
36
|
+
@process_name = process_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_queue_name(queue_name)
|
40
|
+
@queue_name = queue_name
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_min_dynos(min_dynos)
|
44
|
+
@min_dynos = min_dynos
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_max_dynos(max_dynos)
|
48
|
+
@max_dynos = max_dynos
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_scaling_step(scaling_step)
|
52
|
+
@scaling_step = scaling_step
|
53
|
+
end
|
54
|
+
|
55
|
+
def manage_queue
|
56
|
+
scale_to = calculate_number_of_needed_dynos
|
57
|
+
heroku_operations.execute_dyno_scale(process_name, scale_to)
|
58
|
+
end
|
59
|
+
|
60
|
+
def calculate_number_of_needed_dynos
|
61
|
+
current_jobs = get_number_of_jobs_inside_queue
|
62
|
+
dynos = (current_jobs.to_f / scaling_step.to_f).ceil
|
63
|
+
|
64
|
+
scale_to = [dynos, max_dynos].min
|
65
|
+
scale_to = [scale_to, min_dynos].max
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def init_redis_operations
|
70
|
+
@redis_operations = HerokuAutoScale::RedisOperations.new(redis_url)
|
71
|
+
end
|
72
|
+
|
73
|
+
def init_heroku_operations
|
74
|
+
@heroku_operations = HerokuAutoScale::
|
75
|
+
HerokuOperations.new(
|
76
|
+
heroku_oauth_token,
|
77
|
+
heroku_app_name
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module HerokuAutoScale
|
4
|
+
class RedisOperations
|
5
|
+
attr_reader :redis_connection
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@redis_connection = Redis.new(url: url)
|
9
|
+
end
|
10
|
+
|
11
|
+
def check_queue_for_jobs(queue_name)
|
12
|
+
check_queue(queue_name)
|
13
|
+
redis_connection.llen(queue_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def check_queue(queue_name)
|
18
|
+
available_keys = redis_connection.keys
|
19
|
+
unless available_keys.include?(queue_name)
|
20
|
+
raise "There is no key #{queue_name}, \n
|
21
|
+
available keys are:\n
|
22
|
+
#{available_keys}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HerokuAutoScale::Configuration do
|
4
|
+
subject do
|
5
|
+
Object.new.extend(HerokuAutoScale::Configuration)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'allows to set allowed attributes' do
|
9
|
+
subject.configure do |c|
|
10
|
+
c.redis_url = 'url'
|
11
|
+
c.heroku_oauth_token = 'token'
|
12
|
+
c.heroku_app_name = 'app'
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(subject.redis_url).to eq('url')
|
16
|
+
expect(subject.heroku_oauth_token).to eq('token')
|
17
|
+
expect(subject.heroku_app_name).to eq('app')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'retuns hash of it\'s attributes' do
|
21
|
+
subject.configure do |c|
|
22
|
+
c.redis_url = 'url'
|
23
|
+
c.heroku_oauth_token = 'token'
|
24
|
+
c.heroku_app_name = 'app'
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(subject.options).to eq({
|
28
|
+
:redis_url=>"url",
|
29
|
+
:heroku_oauth_token=>"token",
|
30
|
+
:heroku_app_name=>"app"
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HerokuAutoScale::HerokuOperations do
|
4
|
+
subject { HerokuAutoScale::HerokuOperations.new("api_key", "app_name") }
|
5
|
+
|
6
|
+
let(:heroku_info_response) do
|
7
|
+
{
|
8
|
+
"command" => "bundle exec fake_process_name",
|
9
|
+
"created_at" => "2015-04-13T11:36:03Z",
|
10
|
+
"id" => "xxx-xxx-xxx-xxx",
|
11
|
+
"type" => "sidekiq_followers",
|
12
|
+
"quantity" => 1,
|
13
|
+
"size" => "2X",
|
14
|
+
"updated_at" => "2015-05-10T17:26:08Z"
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'should_scale?' do
|
19
|
+
it 'doesn\'t allow to scale for the same no. of dynos' do
|
20
|
+
allow(subject).to receive_message_chain(:heroku_connection, :formation, :info).
|
21
|
+
and_return(heroku_info_response)
|
22
|
+
expect(subject.send(:should_scale?, "process_name", 1)).to eq(false)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does allow to scale for the greater no. of dynos' do
|
26
|
+
allow(subject).to receive_message_chain(:heroku_connection, :formation, :info).
|
27
|
+
and_return(heroku_info_response)
|
28
|
+
expect(subject.send(:should_scale?, "process_name", 2)).to eq(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does allow to scale for the smaller no. of dynos' do
|
32
|
+
allow(subject).to receive_message_chain(:heroku_connection, :formation, :info).
|
33
|
+
and_return(heroku_info_response)
|
34
|
+
expect(subject.send(:should_scale?, "process_name", 0)).to eq(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HerokuAutoScale::Manager do
|
4
|
+
let(:redis_test_url_for_test) { "redis://localhost" }
|
5
|
+
let(:heroku_oauth_token_for_test) { "token" }
|
6
|
+
let(:heroku_app_name_for_test) { "app" }
|
7
|
+
let(:config_values) do
|
8
|
+
[
|
9
|
+
redis_test_url_for_test,
|
10
|
+
heroku_oauth_token_for_test,
|
11
|
+
heroku_app_name_for_test
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
@keys = HerokuAutoScale::Configuration::CONFIGURATION_OPTIONS
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'configuration' do
|
20
|
+
before(:each) do
|
21
|
+
HerokuAutoScale.configure do |c|
|
22
|
+
c.redis_url = redis_test_url_for_test
|
23
|
+
c.heroku_oauth_token = heroku_oauth_token_for_test
|
24
|
+
c.heroku_app_name = heroku_app_name_for_test
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should inherit the config' do
|
29
|
+
manager = HerokuAutoScale::Manager.new
|
30
|
+
@keys.each do |key|
|
31
|
+
expect(
|
32
|
+
config_values.include?(manager.send(key))
|
33
|
+
).to eq(true)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'accepting attributes' do
|
39
|
+
let(:manager) { HerokuAutoScale::Manager.new }
|
40
|
+
|
41
|
+
it '#set_process_name' do
|
42
|
+
manager.set_process_name("some_process_name")
|
43
|
+
expect(manager.process_name).to eq("some_process_name")
|
44
|
+
end
|
45
|
+
|
46
|
+
it '#set_queue_name' do
|
47
|
+
manager.set_queue_name("some_queue_name")
|
48
|
+
expect(manager.queue_name).to eq("some_queue_name")
|
49
|
+
end
|
50
|
+
|
51
|
+
it '#set_min_dynos' do
|
52
|
+
manager.set_min_dynos(1)
|
53
|
+
expect(manager.min_dynos).to eq(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
it '#set_max_dynos' do
|
57
|
+
manager.set_max_dynos(2)
|
58
|
+
expect(manager.max_dynos).to eq(2)
|
59
|
+
end
|
60
|
+
|
61
|
+
it '#set_scaling_step' do
|
62
|
+
manager.set_scaling_step(12000)
|
63
|
+
expect(manager.scaling_step).to eq(12000)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'dynos numbers for scalability' do
|
69
|
+
let(:manager) { HerokuAutoScale::Manager.new }
|
70
|
+
|
71
|
+
it 'sets 0 dynos when there are no jobs and min_dynos(0)' do
|
72
|
+
manager.set_scaling_step(10_000)
|
73
|
+
manager.set_min_dynos(0)
|
74
|
+
manager.set_max_dynos(10)
|
75
|
+
allow(manager).to receive(:get_number_of_jobs_inside_queue) { 0 }
|
76
|
+
|
77
|
+
expect(manager.calculate_number_of_needed_dynos).to eq(0)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'sets to min dynos when there are no jobs and min_dynos(1)' do
|
81
|
+
manager.set_scaling_step(10_000)
|
82
|
+
manager.set_min_dynos(1)
|
83
|
+
manager.set_max_dynos(10)
|
84
|
+
allow(manager).to receive(:get_number_of_jobs_inside_queue) { 0 }
|
85
|
+
|
86
|
+
expect(manager.calculate_number_of_needed_dynos).to eq(1)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'sets 1 dynos when there are jobs till the first scaling_step' do
|
90
|
+
manager.set_scaling_step(10_000)
|
91
|
+
manager.set_min_dynos(0)
|
92
|
+
manager.set_max_dynos(10)
|
93
|
+
allow(manager).to receive(:get_number_of_jobs_inside_queue) { 8_000 }
|
94
|
+
|
95
|
+
expect(manager.calculate_number_of_needed_dynos).to eq(1)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'sets 2 dynos when there are jobs till the second scaling_step' do
|
99
|
+
manager.set_scaling_step(10_000)
|
100
|
+
manager.set_min_dynos(0)
|
101
|
+
manager.set_max_dynos(10)
|
102
|
+
allow(manager).to receive(:get_number_of_jobs_inside_queue) { 18_000 }
|
103
|
+
|
104
|
+
expect(manager.calculate_number_of_needed_dynos).to eq(2)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'sets max allowed dynos when there are jobs that exceed max_dynos x scaling_step' do
|
108
|
+
manager.set_scaling_step(10_000)
|
109
|
+
manager.set_min_dynos(0)
|
110
|
+
manager.set_max_dynos(4)
|
111
|
+
allow(manager).to receive(:get_number_of_jobs_inside_queue) { 180_000 }
|
112
|
+
|
113
|
+
expect(manager.calculate_number_of_needed_dynos).to eq(4)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/collection_matchers'
|
4
|
+
require 'heroku_auto_scale'
|
5
|
+
require 'webmock/rspec'
|
6
|
+
|
7
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.mock_framework = :rspec
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: heroku_auto_scale
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- luki3k5
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: platform-api
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-collection_matchers
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: awesome_print
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Simple DSL for creating scaling rules for worker dynos on Heroku
|
140
|
+
email:
|
141
|
+
- luki3k5@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
148
|
+
- Gemfile
|
149
|
+
- LICENSE.txt
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- heroku_auto_scale.gemspec
|
153
|
+
- lib/heroku_auto_scale.rb
|
154
|
+
- lib/heroku_auto_scale/configuration.rb
|
155
|
+
- lib/heroku_auto_scale/heroku_operations.rb
|
156
|
+
- lib/heroku_auto_scale/manager.rb
|
157
|
+
- lib/heroku_auto_scale/redis_operations.rb
|
158
|
+
- lib/heroku_auto_scale/version.rb
|
159
|
+
- spec/heroku_auto_scale/configuration_spec.rb
|
160
|
+
- spec/heroku_auto_scale/heroku_operations_spec.rb
|
161
|
+
- spec/heroku_auto_scale/manager_spec.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
homepage: ''
|
164
|
+
licenses:
|
165
|
+
- MIT
|
166
|
+
metadata: {}
|
167
|
+
post_install_message:
|
168
|
+
rdoc_options: []
|
169
|
+
require_paths:
|
170
|
+
- lib
|
171
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
requirements: []
|
182
|
+
rubyforge_project:
|
183
|
+
rubygems_version: 2.4.3
|
184
|
+
signing_key:
|
185
|
+
specification_version: 4
|
186
|
+
summary: Simple DSL for creating scaling rules for worker dynos on Heroku
|
187
|
+
test_files:
|
188
|
+
- spec/heroku_auto_scale/configuration_spec.rb
|
189
|
+
- spec/heroku_auto_scale/heroku_operations_spec.rb
|
190
|
+
- spec/heroku_auto_scale/manager_spec.rb
|
191
|
+
- spec/spec_helper.rb
|