autoscale 0.9.3 → 0.11.0

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -2
  3. data/README.md +19 -13
  4. data/examples/complex.rb +3 -3
  5. data/examples/simple.rb +2 -2
  6. data/lib/autoscaler/binary_scaling_strategy.rb +1 -1
  7. data/lib/autoscaler/heroku_platform_scaler.rb +84 -0
  8. data/lib/autoscaler/ignore_scheduled_and_retrying.rb +5 -0
  9. data/lib/autoscaler/linear_scaling_strategy.rb +1 -1
  10. data/lib/autoscaler/sidekiq.rb +2 -2
  11. data/lib/autoscaler/sidekiq/client.rb +1 -1
  12. data/lib/autoscaler/sidekiq/entire_queue_system.rb +10 -0
  13. data/lib/autoscaler/sidekiq/sleep_wait_server.rb +2 -2
  14. data/lib/autoscaler/sidekiq/specified_queue_system.rb +10 -0
  15. data/lib/autoscaler/sidekiq/thread_server.rb +90 -0
  16. data/lib/autoscaler/version.rb +1 -1
  17. data/spec/autoscaler/binary_scaling_strategy_spec.rb +2 -2
  18. data/spec/autoscaler/counter_cache_memory_spec.rb +3 -3
  19. data/spec/autoscaler/counter_cache_redis_spec.rb +6 -6
  20. data/spec/autoscaler/delayed_shutdown_spec.rb +4 -4
  21. data/spec/autoscaler/heroku_platform_scaler_spec.rb +47 -0
  22. data/spec/autoscaler/heroku_scaler_spec.rb +8 -8
  23. data/spec/autoscaler/ignore_scheduled_and_retrying_spec.rb +4 -4
  24. data/spec/autoscaler/linear_scaling_strategy_spec.rb +13 -13
  25. data/spec/autoscaler/sidekiq/activity_spec.rb +4 -4
  26. data/spec/autoscaler/sidekiq/client_spec.rb +5 -5
  27. data/spec/autoscaler/sidekiq/entire_queue_system_spec.rb +11 -11
  28. data/spec/autoscaler/sidekiq/sleep_wait_server_spec.rb +21 -21
  29. data/spec/autoscaler/sidekiq/specified_queue_system_spec.rb +10 -10
  30. data/spec/autoscaler/sidekiq/thread_server_spec.rb +44 -0
  31. data/spec/spec_helper.rb +4 -2
  32. data/spec/test_system.rb +6 -0
  33. metadata +71 -15
  34. data/lib/autoscaler/sidekiq/celluloid_monitor.rb +0 -68
  35. data/lib/autoscaler/sidekiq/monitor_middleware_adapter.rb +0 -46
  36. data/spec/autoscaler/sidekiq/celluloid_monitor_spec.rb +0 -39
  37. data/spec/autoscaler/sidekiq/monitor_middleware_adapter_spec.rb +0 -16
@@ -24,40 +24,40 @@ describe Autoscaler::Sidekiq::SpecifiedQueueSystem do
24
24
 
25
25
  subject {cut.new(['queue'])}
26
26
 
27
- it {subject.queue_names.should == ['queue']}
28
- it {subject.workers.should == 0}
27
+ it {expect(subject.queue_names).to eq ['queue']}
28
+ it {expect(subject.workers).to eq 0}
29
29
 
30
30
  describe 'no queued work' do
31
31
  it "with no work" do
32
- subject.stub(:sidekiq_queues).and_return({'queue' => 0, 'another_queue' => 1})
33
- subject.queued.should == 0
32
+ allow(subject).to receive(:sidekiq_queues).and_return({'queue' => 0, 'another_queue' => 1})
33
+ expect(subject.queued).to eq 0
34
34
  end
35
35
 
36
36
  it "with scheduled work in another queue" do
37
37
  with_scheduled_work_in('another_queue')
38
- subject.scheduled.should == 0
38
+ expect(subject.scheduled).to eq 0
39
39
  end
40
40
 
41
41
  it "with retry work in another queue" do
42
42
  with_retry_work_in('another_queue')
43
- subject.retrying.should == 0
43
+ expect(subject.retrying).to eq 0
44
44
  end
45
45
  end
46
46
 
47
47
  describe 'with queued work' do
48
48
  it "with enqueued work" do
49
- subject.stub(:sidekiq_queues).and_return({'queue' => 1})
50
- subject.queued.should == 1
49
+ allow(subject).to receive(:sidekiq_queues).and_return({'queue' => 1})
50
+ expect(subject.queued).to eq 1
51
51
  end
52
52
 
53
53
  it "with schedule work" do
54
54
  with_scheduled_work_in('queue')
55
- subject.scheduled.should == 1
55
+ expect(subject.scheduled).to eq 1
56
56
  end
57
57
 
58
58
  it "with retry work" do
59
59
  with_retry_work_in('queue')
60
- subject.retrying.should == 1
60
+ expect(subject.retrying).to eq 1
61
61
  end
62
62
  end
63
63
  end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'autoscaler/sidekiq/thread_server'
3
+ require 'timeout'
4
+
5
+ describe Autoscaler::Sidekiq::ThreadServer do
6
+ before do
7
+ @redis = Sidekiq.redis = REDIS
8
+ Sidekiq.redis {|c| c.flushdb }
9
+ end
10
+
11
+ let(:cut) {Autoscaler::Sidekiq::ThreadServer}
12
+ let(:scaler) {TestScaler.new(1)}
13
+
14
+ describe "thread core" do
15
+ it "scales with no work" do
16
+ server = cut.new(scaler, lambda{|s,t| 0})
17
+ Timeout.timeout(1) { server.run(0.5) }
18
+ expect(scaler.workers).to eq 0
19
+ server.terminate
20
+ end
21
+
22
+ it "does not scale with pending work" do
23
+ server = cut.new(scaler, lambda{|s,t| 1})
24
+ expect {Timeout.timeout(1) { server.run(0.5) }}.to raise_error Timeout::Error
25
+ expect(scaler.workers).to eq 1
26
+ server.terminate
27
+ end
28
+
29
+ it "will downscale with initial workers zero" do
30
+ scaler = TestScaler.new(0)
31
+ server = cut.new(scaler, lambda{|s,t| 0})
32
+ Timeout.timeout(1) { server.run(0.5) }
33
+ expect(scaler.workers).to eq 0
34
+ server.terminate
35
+ end
36
+ end
37
+
38
+ describe "Middleware interface" do
39
+ let(:server) {cut.new(scaler, 0, ['queue'])}
40
+
41
+ it('yields') {expect(server.call(Object.new, {}, 'queue') {:foo}).to eq :foo}
42
+ it('yields with a redis pool') {expect(server.call(Object.new, {}, 'queue', Sidekiq.method(:redis)) {:foo}).to eq :foo}
43
+ end
44
+ end
@@ -1,10 +1,12 @@
1
+ require 'rspec/its'
1
2
  require 'sidekiq'
2
- REDIS = Sidekiq::RedisConnection.create(:url => 'http://localhost:9736', :namespace => 'autoscaler')
3
+ REDIS = Sidekiq::RedisConnection.create(:url => 'redis://localhost:9736', :namespace => 'autoscaler')
3
4
 
4
5
  RSpec.configure do |config|
5
6
  config.mock_with :rspec
6
7
 
7
- config.filter_run_excluding :online => true unless ENV['HEROKU_APP']
8
+ config.filter_run_excluding :api1 => true unless ENV['HEROKU_API_KEY']
9
+ config.filter_run_excluding :platform_api => true unless ENV['HEROKU_ACCESS_TOKEN']
8
10
  end
9
11
 
10
12
  class TestScaler
@@ -8,4 +8,10 @@ class TestSystem
8
8
  def queued; @pending; end
9
9
  def scheduled; 0; end
10
10
  def retrying; 0; end
11
+ def total_work
12
+ queued + scheduled + retrying + workers
13
+ end
14
+ def any_work?
15
+ queued > 0 || scheduled > 0 || retrying > 0 || workers > 0
16
+ end
11
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: autoscale
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Love
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-13 00:00:00.000000000 Z
12
+ date: 2015-11-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '3.5'
20
+ version: '4.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '3.5'
27
+ version: '4.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: heroku-api
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: platform-api
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: bundler
44
58
  requirement: !ruby/object:Gem::Requirement
@@ -57,16 +71,58 @@ dependencies:
57
71
  name: rspec
58
72
  requirement: !ruby/object:Gem::Requirement
59
73
  requirements:
60
- - - "<"
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec-its
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: guard-rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: guard-process
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
61
117
  - !ruby/object:Gem::Version
62
- version: '3'
118
+ version: '0'
63
119
  type: :development
64
120
  prerelease: false
65
121
  version_requirements: !ruby/object:Gem::Requirement
66
122
  requirements:
67
- - - "<"
123
+ - - ">="
68
124
  - !ruby/object:Gem::Version
69
- version: '3'
125
+ version: '0'
70
126
  description: Currently provides a Sidekiq middleware that does 0/1 scaling of Heroku
71
127
  processes
72
128
  email:
@@ -85,37 +141,37 @@ files:
85
141
  - lib/autoscaler/counter_cache_memory.rb
86
142
  - lib/autoscaler/counter_cache_redis.rb
87
143
  - lib/autoscaler/delayed_shutdown.rb
144
+ - lib/autoscaler/heroku_platform_scaler.rb
88
145
  - lib/autoscaler/heroku_scaler.rb
89
146
  - lib/autoscaler/ignore_scheduled_and_retrying.rb
90
147
  - lib/autoscaler/linear_scaling_strategy.rb
91
148
  - lib/autoscaler/sidekiq.rb
92
149
  - lib/autoscaler/sidekiq/activity.rb
93
- - lib/autoscaler/sidekiq/celluloid_monitor.rb
94
150
  - lib/autoscaler/sidekiq/client.rb
95
151
  - lib/autoscaler/sidekiq/entire_queue_system.rb
96
- - lib/autoscaler/sidekiq/monitor_middleware_adapter.rb
97
152
  - lib/autoscaler/sidekiq/queue_system.rb
98
153
  - lib/autoscaler/sidekiq/sleep_wait_server.rb
99
154
  - lib/autoscaler/sidekiq/specified_queue_system.rb
155
+ - lib/autoscaler/sidekiq/thread_server.rb
100
156
  - lib/autoscaler/stub_scaler.rb
101
157
  - lib/autoscaler/version.rb
102
158
  - spec/autoscaler/binary_scaling_strategy_spec.rb
103
159
  - spec/autoscaler/counter_cache_memory_spec.rb
104
160
  - spec/autoscaler/counter_cache_redis_spec.rb
105
161
  - spec/autoscaler/delayed_shutdown_spec.rb
162
+ - spec/autoscaler/heroku_platform_scaler_spec.rb
106
163
  - spec/autoscaler/heroku_scaler_spec.rb
107
164
  - spec/autoscaler/ignore_scheduled_and_retrying_spec.rb
108
165
  - spec/autoscaler/linear_scaling_strategy_spec.rb
109
166
  - spec/autoscaler/sidekiq/activity_spec.rb
110
- - spec/autoscaler/sidekiq/celluloid_monitor_spec.rb
111
167
  - spec/autoscaler/sidekiq/client_spec.rb
112
168
  - spec/autoscaler/sidekiq/entire_queue_system_spec.rb
113
- - spec/autoscaler/sidekiq/monitor_middleware_adapter_spec.rb
114
169
  - spec/autoscaler/sidekiq/sleep_wait_server_spec.rb
115
170
  - spec/autoscaler/sidekiq/specified_queue_system_spec.rb
171
+ - spec/autoscaler/sidekiq/thread_server_spec.rb
116
172
  - spec/spec_helper.rb
117
173
  - spec/test_system.rb
118
- homepage: ''
174
+ homepage: https://github.com/JustinLove/autoscaler
119
175
  licenses: []
120
176
  metadata: {}
121
177
  post_install_message:
@@ -144,16 +200,16 @@ test_files:
144
200
  - spec/autoscaler/counter_cache_memory_spec.rb
145
201
  - spec/autoscaler/counter_cache_redis_spec.rb
146
202
  - spec/autoscaler/delayed_shutdown_spec.rb
203
+ - spec/autoscaler/heroku_platform_scaler_spec.rb
147
204
  - spec/autoscaler/heroku_scaler_spec.rb
148
205
  - spec/autoscaler/ignore_scheduled_and_retrying_spec.rb
149
206
  - spec/autoscaler/linear_scaling_strategy_spec.rb
150
207
  - spec/autoscaler/sidekiq/activity_spec.rb
151
- - spec/autoscaler/sidekiq/celluloid_monitor_spec.rb
152
208
  - spec/autoscaler/sidekiq/client_spec.rb
153
209
  - spec/autoscaler/sidekiq/entire_queue_system_spec.rb
154
- - spec/autoscaler/sidekiq/monitor_middleware_adapter_spec.rb
155
210
  - spec/autoscaler/sidekiq/sleep_wait_server_spec.rb
156
211
  - spec/autoscaler/sidekiq/specified_queue_system_spec.rb
212
+ - spec/autoscaler/sidekiq/thread_server_spec.rb
157
213
  - spec/spec_helper.rb
158
214
  - spec/test_system.rb
159
215
  has_rdoc:
@@ -1,68 +0,0 @@
1
- require 'celluloid'
2
- require 'celluloid/supervision/deprecate'
3
-
4
- module Autoscaler
5
- module Sidekiq
6
- # Actor to monitor the sidekiq server for scale-down
7
- class CelluloidMonitor
8
- include Celluloid
9
-
10
- # @param [scaler] scaler object that actually performs scaling operations (e.g. {HerokuScaler})
11
- # @param [Strategy] strategy object that decides the target number of workers (e.g. {BinaryScalingStrategy})
12
- # @param [System] system interface to the queuing system for use by the strategy
13
- def initialize(scaler, strategy, system)
14
- @scaler = scaler
15
- @strategy = strategy
16
- @system = system
17
- @running = false
18
- end
19
-
20
- # Periodically update the desired number of workers
21
- # @param [Numeric] interval polling interval, mostly for testing
22
- def wait_for_downscale(interval = 15)
23
- once do
24
- active_now!
25
-
26
- workers = :unknown
27
-
28
- begin
29
- sleep(interval)
30
- target_workers = @strategy.call(@system, idle_time)
31
- workers = @scaler.workers = target_workers unless workers == target_workers
32
- end while workers > 0
33
- end
34
- end
35
-
36
- # Notify the monitor that a job is starting
37
- def starting_job
38
- end
39
-
40
- # Notify the monitor that a job has finished
41
- def finished_job
42
- active_now!
43
- async.wait_for_downscale
44
- end
45
-
46
- private
47
-
48
- def active_now!
49
- @activity = Time.now
50
- end
51
-
52
- def idle_time
53
- Time.now - @activity
54
- end
55
-
56
- def once
57
- return if @running
58
-
59
- begin
60
- @running = true
61
- yield
62
- ensure
63
- @running = false
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,46 +0,0 @@
1
- require 'autoscaler/sidekiq/queue_system'
2
- require 'autoscaler/sidekiq/celluloid_monitor'
3
- require 'autoscaler/binary_scaling_strategy'
4
- require 'autoscaler/delayed_shutdown'
5
-
6
- module Autoscaler
7
- module Sidekiq
8
- # Shim to the existing autoscaler interface
9
- # Starts the monitor and notifies it of job events that may occur while it's sleeping
10
- class MonitorMiddlewareAdapter
11
- # @param [scaler] scaler object that actually performs scaling operations (e.g. {HerokuScaler})
12
- # @param [Strategy,Numeric] timeout strategy object that determines target workers, or a timeout in seconds to be passed to {DelayedShutdown}+{BinaryScalingStrategy}
13
- # @param [Array[String]] specified_queues list of queues to monitor to determine if there is work left. Defaults to all sidekiq queues.
14
- def initialize(scaler, timeout, specified_queues = nil)
15
- unless monitor
16
- CelluloidMonitor.supervise_as(:autoscaler_monitor,
17
- scaler,
18
- strategy(timeout),
19
- QueueSystem.new(specified_queues))
20
- end
21
- end
22
-
23
- # Sidekiq middleware api entry point
24
- def call(worker, msg, queue, _ = nil)
25
- monitor.async.starting_job
26
- yield
27
- ensure
28
- # monitor might have gone, e.g. if Sidekiq has received SIGTERM
29
- monitor.async.finished_job if monitor
30
- end
31
-
32
- private
33
- def monitor
34
- Celluloid::Actor[:autoscaler_monitor]
35
- end
36
-
37
- def strategy(timeout)
38
- if timeout.respond_to?(:call)
39
- timeout
40
- else
41
- DelayedShutdown.new(BinaryScalingStrategy.new, timeout)
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,39 +0,0 @@
1
- require 'spec_helper'
2
- require 'test_system'
3
- require 'autoscaler/sidekiq/celluloid_monitor'
4
- require 'timeout'
5
-
6
- describe Autoscaler::Sidekiq::CelluloidMonitor do
7
- before do
8
- @redis = Sidekiq.redis = REDIS
9
- Sidekiq.redis {|c| c.flushdb }
10
- end
11
-
12
- let(:cut) {Autoscaler::Sidekiq::CelluloidMonitor}
13
- let(:scaler) {TestScaler.new(1)}
14
-
15
- it "scales with no work" do
16
- system = TestSystem.new(0)
17
- manager = cut.new(scaler, lambda{|s,t| 0}, system)
18
- Timeout.timeout(1) { manager.wait_for_downscale(0.5) }
19
- scaler.workers.should == 0
20
- manager.terminate
21
- end
22
-
23
- it "does not scale with pending work" do
24
- system = TestSystem.new(1)
25
- manager = cut.new(scaler, lambda{|s,t| 1}, system)
26
- expect {Timeout.timeout(1) { manager.wait_for_downscale(0.5) }}.to raise_error Timeout::Error
27
- scaler.workers.should == 1
28
- manager.terminate
29
- end
30
-
31
- it "will downscale with initial workers zero" do
32
- system = TestSystem.new(0)
33
- scaler = TestScaler.new(0)
34
- manager = cut.new(scaler, lambda{|s,t| 0}, system)
35
- Timeout.timeout(1) { manager.wait_for_downscale(0.5) }
36
- scaler.workers.should == 0
37
- manager.terminate
38
- end
39
- end