autoscaler 0.1.0 → 0.2.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.
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/examples/complex.rb +0 -1
- data/examples/simple.rb +0 -1
- data/lib/autoscaler/sidekiq.rb +20 -15
- data/lib/autoscaler/version.rb +1 -1
- data/spec/autoscaler/sidekiq_spec.rb +76 -26
- metadata +12 -6
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.0
|
4
|
+
|
5
|
+
- Raise minimum Sidekiq version to 2.6.1 to take advantage of Stats API
|
6
|
+
- Inspect scheduled and retry sets to see if they match `specified_queues`
|
7
|
+
- Testing: Refactor server middleware tests
|
8
|
+
|
3
9
|
## 0.1.0
|
4
10
|
|
5
11
|
- The `retry` and `scheduled` queues are now considered for shutdown
|
data/README.md
CHANGED
@@ -58,7 +58,7 @@ Justin Love, [@wondible](http://twitter.com/wondible), [https://github.com/Justi
|
|
58
58
|
|
59
59
|
Ported to Heroku-Api by Fix Peña, [https://github.com/fixr](https://github.com/fixr)
|
60
60
|
|
61
|
-
Retry/schedule
|
61
|
+
Retry/schedule sets by Matt Anderson [https://github.com/tonkapark](https://github.com/tonkapark) and Thibaud Guillaume-Gentil [https://github.com/jilion](https://github.com/jilion)
|
62
62
|
|
63
63
|
## Licence
|
64
64
|
|
data/examples/complex.rb
CHANGED
data/examples/simple.rb
CHANGED
data/lib/autoscaler/sidekiq.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'securerandom' # bug in Sidekiq as of 2.2.1
|
2
1
|
require 'sidekiq'
|
3
2
|
|
4
3
|
module Autoscaler
|
@@ -42,35 +41,41 @@ module Autoscaler
|
|
42
41
|
end
|
43
42
|
|
44
43
|
private
|
45
|
-
def
|
46
|
-
@
|
44
|
+
def refresh_sidekiq_queues!
|
45
|
+
@sidekiq_queues = ::Sidekiq::Stats.new.queues
|
47
46
|
end
|
48
47
|
|
49
|
-
|
50
|
-
|
48
|
+
attr_reader :sidekiq_queues
|
49
|
+
|
50
|
+
def queue_names
|
51
|
+
(@specified_queues || sidekiq_queues.keys)
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
-
|
54
|
+
def queued_work?
|
55
|
+
queue_names.any? {|name| sidekiq_queues[name].to_i > 0 }
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
def scheduled_work?
|
58
|
-
|
59
|
+
empty_sorted_set?("schedule")
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
def retry_work?
|
62
|
-
|
63
|
-
end
|
63
|
+
empty_sorted_set?("retry")
|
64
|
+
end
|
65
|
+
|
66
|
+
def empty_sorted_set?(sorted_set)
|
67
|
+
ss = ::Sidekiq::SortedSet.new(sorted_set)
|
68
|
+
ss.any? { |job| queue_names.include?(job.queue) }
|
69
|
+
end
|
64
70
|
|
65
71
|
def pending_work?
|
66
|
-
|
72
|
+
refresh_sidekiq_queues!
|
73
|
+
queued_work? || scheduled_work? || retry_work?
|
67
74
|
end
|
68
75
|
|
69
76
|
def wait_for_task_or_scale
|
70
77
|
loop do
|
71
78
|
return if pending_work?
|
72
|
-
return if scheduled_work?
|
73
|
-
return if retry_work?
|
74
79
|
return @scaler.workers = 0 if idle?
|
75
80
|
sleep(0.5)
|
76
81
|
end
|
data/lib/autoscaler/version.rb
CHANGED
@@ -14,60 +14,110 @@ describe Autoscaler::Sidekiq do
|
|
14
14
|
@redis = Sidekiq.redis = REDIS
|
15
15
|
Sidekiq.redis {|c| c.flushdb }
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
let(:scaler) do
|
19
19
|
Scaler.new(workers)
|
20
20
|
end
|
21
21
|
|
22
22
|
describe Autoscaler::Sidekiq::Client do
|
23
23
|
let(:cut) {Autoscaler::Sidekiq::Client}
|
24
|
-
let(:
|
24
|
+
let(:client) {cut.new('queue' => scaler)}
|
25
25
|
let(:workers) {0}
|
26
26
|
|
27
27
|
describe 'scales' do
|
28
|
-
before {
|
29
|
-
|
30
|
-
it {should == 1}
|
28
|
+
before {client.call(Class, {}, 'queue') {}}
|
29
|
+
it {scaler.workers.should == 1}
|
31
30
|
end
|
32
31
|
|
33
32
|
describe 'yields' do
|
34
|
-
it {
|
33
|
+
it {client.call(Class, {}, 'queue') {:foo}.should == :foo}
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
describe Autoscaler::Sidekiq::Server do
|
39
38
|
let(:cut) {Autoscaler::Sidekiq::Server}
|
40
|
-
let(:
|
39
|
+
let(:server) {cut.new(scaler, 0, ['queue'])}
|
41
40
|
let(:workers) {1}
|
42
41
|
|
42
|
+
def with_work_in_set(queue, set)
|
43
|
+
payload = Sidekiq.dump_json('queue' => queue)
|
44
|
+
Sidekiq.redis { |c| c.zadd(set, (Time.now.to_f + 30.to_f).to_s, payload)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_scheduled_work_in(queue)
|
48
|
+
with_work_in_set(queue, 'schedule')
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_retry_work_in(queue)
|
52
|
+
with_work_in_set(queue, 'retry')
|
53
|
+
end
|
54
|
+
|
55
|
+
def when_run
|
56
|
+
server.call(Object.new, {}, 'queue') {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.when_run_should_scale
|
60
|
+
it('should downscale') do
|
61
|
+
when_run
|
62
|
+
scaler.workers.should == 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.when_run_should_not_scale
|
67
|
+
it('should not downscale') do
|
68
|
+
when_run
|
69
|
+
scaler.workers.should == 1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
43
73
|
describe 'scales' do
|
44
|
-
context "with
|
45
|
-
before
|
46
|
-
|
47
|
-
|
74
|
+
context "with no work" do
|
75
|
+
before do
|
76
|
+
server.stub(:sidekiq_queues).and_return({'queue' => 0, 'another_queue' => 1})
|
77
|
+
end
|
78
|
+
when_run_should_scale
|
79
|
+
end
|
80
|
+
|
81
|
+
context "with scheduled work in another queue" do
|
82
|
+
before do
|
83
|
+
with_scheduled_work_in('another_queue')
|
84
|
+
end
|
85
|
+
when_run_should_scale
|
86
|
+
end
|
87
|
+
|
88
|
+
context "with retry work in another queue" do
|
89
|
+
before do
|
90
|
+
with_retry_work_in('another_queue')
|
91
|
+
end
|
92
|
+
when_run_should_scale
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'does not scale' do
|
97
|
+
context "with enqueued work" do
|
98
|
+
before do
|
99
|
+
server.stub(:sidekiq_queues).and_return({'queue' => 1})
|
100
|
+
end
|
101
|
+
when_run_should_not_scale
|
48
102
|
end
|
49
|
-
|
103
|
+
|
50
104
|
context "with schedule work" do
|
51
|
-
before do
|
52
|
-
|
53
|
-
sa.call(Object.new, {}, 'queue') {}
|
105
|
+
before do
|
106
|
+
with_scheduled_work_in('queue')
|
54
107
|
end
|
55
|
-
|
56
|
-
it {should == 1}
|
108
|
+
when_run_should_not_scale
|
57
109
|
end
|
58
|
-
|
110
|
+
|
59
111
|
context "with retry work" do
|
60
112
|
before do
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
subject {scaler.workers}
|
65
|
-
it {should == 1}
|
113
|
+
with_retry_work_in('queue')
|
114
|
+
end
|
115
|
+
when_run_should_not_scale
|
66
116
|
end
|
67
117
|
end
|
68
|
-
|
118
|
+
|
69
119
|
describe 'yields' do
|
70
|
-
it {
|
71
|
-
end
|
120
|
+
it {server.call(Object.new, {}, 'queue') {:foo}.should == :foo}
|
121
|
+
end
|
72
122
|
end
|
73
123
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autoscaler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,24 +10,30 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-01-
|
13
|
+
date: 2013-01-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sidekiq
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
|
-
- -
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.6.1
|
23
|
+
- - <
|
21
24
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
25
|
+
version: '3.0'
|
23
26
|
type: :runtime
|
24
27
|
prerelease: false
|
25
28
|
version_requirements: !ruby/object:Gem::Requirement
|
26
29
|
none: false
|
27
30
|
requirements:
|
28
|
-
- -
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.6.1
|
34
|
+
- - <
|
29
35
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
36
|
+
version: '3.0'
|
31
37
|
- !ruby/object:Gem::Dependency
|
32
38
|
name: heroku-api
|
33
39
|
requirement: !ruby/object:Gem::Requirement
|