autoscale 0.9.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -8,12 +8,12 @@ describe Autoscaler::BinaryScalingStrategy do
8
8
  it "scales with no work" do
9
9
  system = TestSystem.new(0)
10
10
  strategy = cut.new
11
- strategy.call(system, 1).should == 0
11
+ expect(strategy.call(system, 1)).to eq 0
12
12
  end
13
13
 
14
14
  it "does not scale with pending work" do
15
15
  system = TestSystem.new(1)
16
16
  strategy = cut.new(2)
17
- strategy.call(system, 1).should == 2
17
+ expect(strategy.call(system, 1)).to eq 2
18
18
  end
19
19
  end
@@ -5,17 +5,17 @@ describe Autoscaler::CounterCacheMemory do
5
5
  let(:cut) {Autoscaler::CounterCacheMemory}
6
6
 
7
7
  it {expect{cut.new.counter}.to raise_error(cut::Expired)}
8
- it {cut.new.counter{1}.should == 1}
8
+ it {expect(cut.new.counter{1}).to eq 1}
9
9
 
10
10
  it 'set and store' do
11
11
  cache = cut.new
12
12
  cache.counter = 1
13
- cache.counter.should == 1
13
+ expect(cache.counter).to eq 1
14
14
  end
15
15
 
16
16
  it 'times out' do
17
17
  cache = cut.new(0)
18
18
  cache.counter = 1
19
- expect{cache.counter.should}.to raise_error(cut::Expired)
19
+ expect{cache.counter}.to raise_error(cut::Expired)
20
20
  end
21
21
  end
@@ -11,11 +11,11 @@ describe Autoscaler::CounterCacheRedis do
11
11
  subject {cut.new(Sidekiq.method(:redis))}
12
12
 
13
13
  it {expect{subject.counter}.to raise_error(cut::Expired)}
14
- it {subject.counter{1}.should == 1}
14
+ it {expect(subject.counter{1}).to eq 1}
15
15
 
16
16
  it 'set and store' do
17
17
  subject.counter = 2
18
- subject.counter.should == 2
18
+ expect(subject.counter).to eq 2
19
19
  end
20
20
 
21
21
  it 'does not conflict with multiple worker types' do
@@ -23,7 +23,7 @@ describe Autoscaler::CounterCacheRedis do
23
23
  subject.counter = 1
24
24
  other_worker_cache.counter = 2
25
25
 
26
- subject.counter.should == 1
26
+ expect(subject.counter).to eq 1
27
27
  other_worker_cache.counter = 2
28
28
  end
29
29
 
@@ -37,13 +37,13 @@ describe Autoscaler::CounterCacheRedis do
37
37
  it 'passed a connection pool' do
38
38
  cache = cut.new(@redis)
39
39
  cache.counter = 4
40
- cache.counter.should == 4
40
+ expect(cache.counter).to eq 4
41
41
  end
42
42
 
43
43
  it 'passed a plain connection' do
44
- connection = Redis.connect(:url => 'http://localhost:9736', :namespace => 'autoscaler')
44
+ connection = Redis.connect(:url => 'redis://localhost:9736', :namespace => 'autoscaler')
45
45
  cache = cut.new connection
46
46
  cache.counter = 5
47
- cache.counter.should == 5
47
+ expect(cache.counter).to eq 5
48
48
  end
49
49
  end
@@ -7,17 +7,17 @@ describe Autoscaler::DelayedShutdown do
7
7
 
8
8
  it "returns normal values" do
9
9
  strategy = cut.new(lambda{|s,t| 2}, 0)
10
- strategy.call(nil, 1).should == 2
10
+ expect(strategy.call(nil, 1)).to eq 2
11
11
  end
12
12
 
13
13
  it "delays zeros" do
14
14
  strategy = cut.new(lambda{|s,t| 0}, 60)
15
- strategy.call(nil, 1).should == 1
15
+ expect(strategy.call(nil, 1)).to eq 1
16
16
  end
17
17
 
18
18
  it "eventually returns zero" do
19
19
  strategy = cut.new(lambda{|s,t| 0}, 60)
20
- strategy.stub(:level_idle_time).and_return(61)
21
- strategy.call(nil, 61).should == 0
20
+ allow(strategy).to receive(:level_idle_time).and_return(61)
21
+ expect(strategy.call(nil, 61)).to eq 0
22
22
  end
23
23
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'autoscaler/heroku_platform_scaler'
3
+
4
+ describe Autoscaler::HerokuPlatformScaler, :platform_api => true do
5
+ let(:cut) {Autoscaler::HerokuPlatformScaler}
6
+ let(:client) {cut.new}
7
+ subject {client}
8
+
9
+ its(:workers) {should eq(0)}
10
+
11
+ describe 'scaled' do
12
+ around do |example|
13
+ client.workers = 1
14
+ example.call
15
+ client.workers = 0
16
+ end
17
+
18
+ its(:workers) {should eq(1)}
19
+ end
20
+
21
+ shared_examples 'exception handler' do |exception_class|
22
+ before do
23
+ expect(client).to receive(:client){
24
+ raise exception_class.new(Exception.new('oops'))
25
+ }
26
+ end
27
+
28
+ describe "default handler" do
29
+ it {expect{client.workers}.to_not raise_error}
30
+ it {expect(client.workers).to eq(0)}
31
+ it {expect{client.workers = 2}.to_not raise_error}
32
+ end
33
+
34
+ describe "custom handler" do
35
+ before do
36
+ @caught = false
37
+ client.exception_handler = lambda {|exception| @caught = true}
38
+ end
39
+
40
+ it {client.workers; expect(@caught).to be(true)}
41
+ end
42
+ end
43
+
44
+ describe 'exception handling', :focus => true do
45
+ it_behaves_like 'exception handler', Excon::Errors::Error
46
+ end
47
+ end
@@ -2,33 +2,33 @@ require 'spec_helper'
2
2
  require 'autoscaler/heroku_scaler'
3
3
  require 'heroku/api/errors'
4
4
 
5
- describe Autoscaler::HerokuScaler, :online => true do
5
+ describe Autoscaler::HerokuScaler, :api1 => true do
6
6
  let(:cut) {Autoscaler::HerokuScaler}
7
7
  let(:client) {cut.new}
8
8
  subject {client}
9
9
 
10
- its(:workers) {should == 0}
10
+ its(:workers) {should eq(0)}
11
11
 
12
12
  describe 'scaled' do
13
13
  around do |example|
14
14
  client.workers = 1
15
- example.yield
15
+ example.call
16
16
  client.workers = 0
17
17
  end
18
18
 
19
- its(:workers) {should == 1}
19
+ its(:workers) {should eq(1)}
20
20
  end
21
21
 
22
22
  shared_examples 'exception handler' do |exception_class|
23
23
  before do
24
- client.should_receive(:client){
24
+ expect(client).to receive(:client){
25
25
  raise exception_class.new(Exception.new('oops'))
26
26
  }
27
27
  end
28
28
 
29
29
  describe "default handler" do
30
30
  it {expect{client.workers}.to_not raise_error}
31
- it {client.workers.should == 0}
31
+ it {expect(client.workers).to eq(0)}
32
32
  it {expect{client.workers = 2}.to_not raise_error}
33
33
  end
34
34
 
@@ -38,7 +38,7 @@ describe Autoscaler::HerokuScaler, :online => true do
38
38
  client.exception_handler = lambda {|exception| @caught = true}
39
39
  end
40
40
 
41
- it {client.workers; @caught.should be_true}
41
+ it {client.workers; expect(@caught).to be(true)}
42
42
  end
43
43
  end
44
44
 
@@ -46,4 +46,4 @@ describe Autoscaler::HerokuScaler, :online => true do
46
46
  it_behaves_like 'exception handler', Excon::Errors::SocketError
47
47
  it_behaves_like 'exception handler', Heroku::API::Errors::Error
48
48
  end
49
- end
49
+ end
@@ -8,25 +8,25 @@ describe Autoscaler::IgnoreScheduledAndRetrying do
8
8
  it "passes through enqueued" do
9
9
  system = Struct.new(:enqueued).new(3)
10
10
  strategy = proc {|system, time| system.enqueued}
11
- cut.new(strategy).call(system, 0).should == 3
11
+ expect(cut.new(strategy).call(system, 0)).to eq 3
12
12
  end
13
13
 
14
14
  it "passes through workers" do
15
15
  system = Struct.new(:workers).new(3)
16
16
  strategy = proc {|system, time| system.workers}
17
- cut.new(strategy).call(system, 0).should == 3
17
+ expect(cut.new(strategy).call(system, 0)).to eq 3
18
18
  end
19
19
 
20
20
  it "ignores scheduled" do
21
21
  system = Struct.new(:scheduled).new(3)
22
22
  strategy = proc {|system, time| system.scheduled}
23
- cut.new(strategy).call(system, 0).should == 0
23
+ expect(cut.new(strategy).call(system, 0)).to eq 0
24
24
  end
25
25
 
26
26
  it "ignores retrying" do
27
27
  system = Struct.new(:retrying).new(3)
28
28
  strategy = proc {|system, time| system.retrying}
29
- cut.new(strategy).call(system, 0).should == 0
29
+ expect(cut.new(strategy).call(system, 0)).to eq 0
30
30
  end
31
31
  end
32
32
 
@@ -8,78 +8,78 @@ describe Autoscaler::LinearScalingStrategy do
8
8
  it "deactivates with no work" do
9
9
  system = TestSystem.new(0)
10
10
  strategy = cut.new(1)
11
- strategy.call(system, 1).should == 0
11
+ expect(strategy.call(system, 1)).to eq 0
12
12
  end
13
13
 
14
14
  it "activates with some work" do
15
15
  system = TestSystem.new(1)
16
16
  strategy = cut.new(1)
17
- strategy.call(system, 1).should be > 0
17
+ expect(strategy.call(system, 1)).to be > 0
18
18
  end
19
19
 
20
20
  it "minimally scales with minimal work" do
21
21
  system = TestSystem.new(1)
22
22
  strategy = cut.new(2, 2)
23
- strategy.call(system, 1).should == 1
23
+ expect(strategy.call(system, 1)).to eq 1
24
24
  end
25
25
 
26
26
  it "maximally scales with too much work" do
27
27
  system = TestSystem.new(5)
28
28
  strategy = cut.new(2, 2)
29
- strategy.call(system, 1).should == 2
29
+ expect(strategy.call(system, 1)).to eq 2
30
30
  end
31
31
 
32
32
  it "proportionally scales with some work" do
33
33
  system = TestSystem.new(5)
34
34
  strategy = cut.new(5, 2)
35
- strategy.call(system, 1).should == 3
35
+ expect(strategy.call(system, 1)).to eq 3
36
36
  end
37
37
 
38
38
  it "doesn't scale unless minimum is met" do
39
39
  system = TestSystem.new(2)
40
40
  strategy = cut.new(10, 4, 0.5)
41
- strategy.call(system, 1).should == 0
41
+ expect(strategy.call(system, 1)).to eq 0
42
42
  end
43
43
 
44
44
  it "scales proprotionally with a minimum" do
45
45
  system = TestSystem.new(3)
46
46
  strategy = cut.new(10, 4, 0.5)
47
- strategy.call(system, 1).should == 1
47
+ expect(strategy.call(system, 1)).to eq 1
48
48
  end
49
49
 
50
50
  it "scales maximally with a minimum" do
51
51
  system = TestSystem.new(25)
52
52
  strategy = cut.new(5, 4, 0.5)
53
- strategy.call(system, 1).should == 5
53
+ expect(strategy.call(system, 1)).to eq 5
54
54
  end
55
55
 
56
56
  it "scales proportionally with a minimum > 1" do
57
57
  system = TestSystem.new(12)
58
58
  strategy = cut.new(5, 4, 2)
59
- strategy.call(system, 1).should == 2
59
+ expect(strategy.call(system, 1)).to eq 2
60
60
  end
61
61
 
62
62
  it "scales maximally with a minimum factor > 1" do
63
63
  system = TestSystem.new(30)
64
64
  strategy = cut.new(5, 4, 2)
65
- strategy.call(system, 1).should == 5
65
+ expect(strategy.call(system, 1)).to eq 5
66
66
  end
67
67
 
68
68
  it "doesn't scale down engaged workers" do
69
69
  system = TestSystem.new(0, 2)
70
70
  strategy = cut.new(5, 4)
71
- strategy.call(system, 1).should == 2
71
+ expect(strategy.call(system, 1)).to eq 2
72
72
  end
73
73
 
74
74
  it "doesn't scale above max workers even if engaged workers is greater" do
75
75
  system = TestSystem.new(40, 6)
76
76
  strategy = cut.new(5, 4)
77
- strategy.call(system, 1).should == 5
77
+ expect(strategy.call(system, 1)).to eq 5
78
78
  end
79
79
 
80
80
  it "returns zero if requested capacity is zero" do
81
81
  system = TestSystem.new(0, 0)
82
82
  strategy = cut.new(0, 0)
83
- strategy.call(system, 5).should == 0
83
+ expect(strategy.call(system, 5)).to eq 0
84
84
  end
85
85
  end
@@ -16,19 +16,19 @@ describe Autoscaler::Sidekiq::Activity do
16
16
  activity.idle!('queue')
17
17
  other_process.working!('other_queue')
18
18
  end
19
- it {activity.should be_idle(['queue'])}
19
+ it {expect(activity).to be_idle(['queue'])}
20
20
  end
21
21
 
22
22
  it 'passed a connection pool' do
23
23
  activity = cut.new(5, @redis)
24
24
  activity.working!('queue')
25
- activity.should_not be_idle(['queue'])
25
+ expect(activity).to_not be_idle(['queue'])
26
26
  end
27
27
 
28
28
  it 'passed a plain connection' do
29
- connection = Redis.connect(:url => 'http://localhost:9736', :namespace => 'autoscaler')
29
+ connection = Redis.connect(:url => 'redis://localhost:9736', :namespace => 'autoscaler')
30
30
  activity = cut.new(5, connection)
31
31
  activity.working!('queue')
32
- activity.should_not be_idle(['queue'])
32
+ expect(activity).to_not be_idle(['queue'])
33
33
  end
34
34
  end
@@ -10,26 +10,26 @@ describe Autoscaler::Sidekiq::Client do
10
10
  describe 'call' do
11
11
  it 'scales' do
12
12
  client.call(Class, {}, 'queue') {}
13
- scaler.workers.should == 1
13
+ expect(scaler.workers).to eq 1
14
14
  end
15
15
 
16
16
  it 'scales with a redis pool' do
17
17
  client.call(Class, {}, 'queue', ::Sidekiq.method(:redis)) {}
18
- scaler.workers.should == 1
18
+ expect(scaler.workers).to eq 1
19
19
  end
20
20
 
21
- it('yields') {client.call(Class, {}, 'queue') {:foo}.should == :foo}
21
+ it('yields') {expect(client.call(Class, {}, 'queue') {:foo}).to eq :foo}
22
22
  end
23
23
 
24
24
  describe 'initial workers' do
25
25
  it 'works with default arguments' do
26
26
  client.set_initial_workers
27
- scaler.workers.should == 0
27
+ expect(scaler.workers).to eq 0
28
28
  end
29
29
 
30
30
  it 'scales when necessary' do
31
31
  client.set_initial_workers {|q| TestSystem.new(1)}
32
- scaler.workers.should == 1
32
+ expect(scaler.workers).to eq 1
33
33
  end
34
34
  end
35
35
  end
@@ -24,42 +24,42 @@ describe Autoscaler::Sidekiq::EntireQueueSystem do
24
24
 
25
25
  subject {cut.new}
26
26
 
27
- it {subject.queue_names.should == []}
28
- it {subject.workers.should == 0}
27
+ it {expect(subject.queue_names).to eq []}
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' => 0})
33
- subject.queued.should == 0
32
+ allow(subject).to receive(:sidekiq_queues).and_return({'queue' => 0, 'another_queue' => 0})
33
+ expect(subject.queued).to eq 0
34
34
  end
35
35
 
36
36
  it "with no work and no queues" do
37
- subject.queued.should == 0
37
+ expect(subject.queued).to eq 0
38
38
  end
39
39
 
40
40
  it "with no scheduled work" do
41
- subject.scheduled.should == 0
41
+ expect(subject.scheduled).to eq 0
42
42
  end
43
43
 
44
44
  it "with no retry work" do
45
- subject.retrying.should == 0
45
+ expect(subject.retrying).to eq 0
46
46
  end
47
47
  end
48
48
 
49
49
  describe 'with queued work' do
50
50
  it "with enqueued work" do
51
- subject.stub(:sidekiq_queues).and_return({'queue' => 1})
52
- subject.queued.should == 1
51
+ allow(subject).to receive(:sidekiq_queues).and_return({'queue' => 1})
52
+ expect(subject.queued).to eq 1
53
53
  end
54
54
 
55
55
  it "with schedule work" do
56
56
  with_scheduled_work_in('queue')
57
- subject.scheduled.should == 1
57
+ expect(subject.scheduled).to eq 1
58
58
  end
59
59
 
60
60
  it "with retry work" do
61
61
  with_retry_work_in('queue')
62
- subject.retrying.should == 1
62
+ expect(subject.retrying).to eq 1
63
63
  end
64
64
  end
65
65
  end
@@ -12,34 +12,34 @@ describe Autoscaler::Sidekiq::SleepWaitServer do
12
12
  let(:server) {cut.new(scaler, 0, ['queue'])}
13
13
 
14
14
  shared_examples "a sleepwait server" do
15
- it "scales with no work" do
16
- server.stub(:pending_work?).and_return(false)
17
- when_run
18
- scaler.workers.should == 0
19
- end
15
+ it "scales with no work" do
16
+ allow(server).to receive(:pending_work?).and_return(false)
17
+ when_run
18
+ expect(scaler.workers).to eq 0
19
+ end
20
20
 
21
- it "does not scale with pending work" do
22
- server.stub(:pending_work?).and_return(true)
23
- when_run
24
- scaler.workers.should == 1
25
- end
21
+ it "does not scale with pending work" do
22
+ allow(server).to receive(:pending_work?).and_return(true)
23
+ when_run
24
+ expect(scaler.workers).to eq 1
25
+ end
26
26
  end
27
27
 
28
28
  describe "a middleware with no redis specified" do
29
- it_behaves_like "a sleepwait server" do
30
- def when_run
31
- server.call(Object.new, {}, 'queue') {}
32
- end
33
- end
29
+ it_behaves_like "a sleepwait server" do
30
+ def when_run
31
+ server.call(Object.new, {}, 'queue') {}
32
+ end
33
+ end
34
34
  end
35
35
 
36
36
  describe "a middleware with redis specified" do
37
- it_behaves_like "a sleepwait server" do
38
- def when_run
39
- server.call(Object.new, {}, 'queue', Sidekiq.method(:redis)) {}
40
- end
41
- end
37
+ it_behaves_like "a sleepwait server" do
38
+ def when_run
39
+ server.call(Object.new, {}, 'queue', Sidekiq.method(:redis)) {}
40
+ end
41
+ end
42
42
  end
43
43
 
44
- it('yields') {server.call(Object.new, {}, 'queue') {:foo}.should == :foo}
44
+ it('yields') {expect(server.call(Object.new, {}, 'queue') {:foo}).to eq :foo}
45
45
  end