sidekiq-ecs-scaler 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4d70a0b678343e315f0d8b64c0d8bd5c957277cd0cd6e201d54a2cf2b828240
4
- data.tar.gz: d61d4ed70aad984f619846dfed858ec745db318dab39417749ec0a0c821489dc
3
+ metadata.gz: 61e35b0bdbfd171583e88d98453ff54f2715f4e8b59be4564a40f8f38e015b38
4
+ data.tar.gz: 9f36a75e28df3bb96a25f874d1d071853c9896732445ff5890129775855ebc32
5
5
  SHA512:
6
- metadata.gz: 115d9a719b314f47901711eeefb3ab3015525a5d163a698f868ef9e358ad06a91e9e19b9686102193c8bd9c69d377210929581f90de601aa4d30ff795700a78d
7
- data.tar.gz: 99242f8721633c865b5e6defc1750f6346a5a411c958b97094a3dd19a91b3a0e950856818c571a8231e03843e1383969aaab81e8084a2ca79175cac4937f79b0
6
+ metadata.gz: 766e8fe9659709dea552de8cb0251f26cb14a0741b07e85fed48b6efd5cee3cced89cf018f76e96ddbe2f266f5c283f232e4cbeeab7b2832a9e530495b582f64
7
+ data.tar.gz: bfe755f5c853c03ba32e8e36af3ac9bc241dddcd2e5e636734c08a2560c00dc6926a9b7a494766c491009088d24ec387821e3a22bb5e7dbe65f3a49a81ae92df
data/.rubocop.yml CHANGED
@@ -1,3 +1,9 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rake
4
+ - rubocop-rspec
5
+ - rubocop-thread_safety
6
+
1
7
  AllCops:
2
8
  TargetRubyVersion: 2.6
3
9
  NewCops: enable
@@ -18,4 +24,8 @@ Metrics/BlockLength:
18
24
  - spec/**/*_spec.rb
19
25
 
20
26
  Naming/FileName:
27
+ Exclude:
28
+ - lib/sidekiq-ecs-scaler.rb
29
+
30
+ RSpec/MultipleMemoizedHelpers:
21
31
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.3.0] - 2024-01-03
2
+
3
+ - Abolish non-thread safe configuration.
4
+ - Changed the mechanism to implement workers on the user side.
5
+
1
6
  ## [0.2.0] - 2021-12-01
2
7
 
3
8
  - Add configuration items
data/Dockerfile CHANGED
@@ -1,14 +1,9 @@
1
- FROM ruby:3.0.3-slim
1
+ FROM ruby:3.2.2
2
2
 
3
- RUN apt-get update \
4
- && apt-get install -y build-essential git \
5
- && apt-get clean \
6
- && rm -rf /var/lib/apt/lists/*
3
+ WORKDIR /usr/src/gem
7
4
 
8
- WORKDIR /usr/src/sidekiq-ecs-scaler
9
-
10
- RUN mkdir -p lib/sidekiq-ecs-scaler \
11
- && echo "module SidekiqEcsScaler\n VERSION = \"0.1.0\"\nend\n" > lib/sidekiq-ecs-scaler/version.rb
5
+ RUN mkdir -p lib/sidekiq_ecs_scaler \
6
+ && echo "module SidekiqEcsScaler\n VERSION = \"0.1.0\"\nend\n" > lib/sidekiq_ecs_scaler/version.rb
12
7
 
13
8
  COPY bin/setup ./bin/
14
9
  COPY Gemfile Gemfile.lock sidekiq-ecs-scaler.gemspec .
data/Gemfile CHANGED
@@ -5,11 +5,13 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in sidekiq-ecs-scaler.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake"
9
- gem "rspec"
10
- gem "rubocop"
11
- gem "rubocop-rake"
12
- gem "rubocop-rspec"
13
- gem "simplecov"
14
- gem "steep"
15
- gem "yard"
8
+ gem "rake", require: false
9
+ gem "rspec", require: false
10
+ gem "rubocop", require: false
11
+ gem "rubocop-performance", require: false
12
+ gem "rubocop-rake", require: false
13
+ gem "rubocop-rspec", require: false
14
+ gem "rubocop-thread_safety", require: false
15
+ gem "simplecov", require: false
16
+ gem "steep", require: false
17
+ gem "yard", require: false
data/Gemfile.lock CHANGED
@@ -1,115 +1,157 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sidekiq-ecs-scaler (0.2.0)
4
+ sidekiq-ecs-scaler (0.3.0)
5
5
  aws-sdk-ecs (> 1, < 2)
6
- sidekiq (> 5, < 7)
6
+ sidekiq (> 5, < 8)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (6.1.4.1)
11
+ abbrev (0.1.2)
12
+ activesupport (7.1.2)
13
+ base64
14
+ bigdecimal
12
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ connection_pool (>= 2.2.5)
17
+ drb
13
18
  i18n (>= 1.6, < 2)
14
19
  minitest (>= 5.1)
20
+ mutex_m
15
21
  tzinfo (~> 2.0)
16
- zeitwerk (~> 2.3)
17
22
  ast (2.4.2)
18
- aws-eventstream (1.2.0)
19
- aws-partitions (1.536.0)
20
- aws-sdk-core (3.123.0)
21
- aws-eventstream (~> 1, >= 1.0.2)
22
- aws-partitions (~> 1, >= 1.525.0)
23
- aws-sigv4 (~> 1.1)
24
- jmespath (~> 1.0)
25
- aws-sdk-ecs (1.91.0)
26
- aws-sdk-core (~> 3, >= 3.122.0)
23
+ aws-eventstream (1.3.0)
24
+ aws-partitions (1.876.0)
25
+ aws-sdk-core (3.190.1)
26
+ aws-eventstream (~> 1, >= 1.3.0)
27
+ aws-partitions (~> 1, >= 1.651.0)
28
+ aws-sigv4 (~> 1.8)
29
+ jmespath (~> 1, >= 1.6.1)
30
+ aws-sdk-ecs (1.135.0)
31
+ aws-sdk-core (~> 3, >= 3.188.0)
27
32
  aws-sigv4 (~> 1.1)
28
- aws-sigv4 (1.4.0)
33
+ aws-sigv4 (1.8.0)
29
34
  aws-eventstream (~> 1, >= 1.0.2)
30
- concurrent-ruby (1.1.9)
31
- connection_pool (2.2.5)
32
- diff-lcs (1.4.4)
35
+ base64 (0.2.0)
36
+ bigdecimal (3.1.5)
37
+ concurrent-ruby (1.2.2)
38
+ connection_pool (2.4.1)
39
+ csv (3.2.8)
40
+ diff-lcs (1.5.0)
33
41
  docile (1.4.0)
34
- ffi (1.15.4)
35
- i18n (1.8.11)
42
+ drb (2.2.0)
43
+ ruby2_keywords
44
+ ffi (1.16.3)
45
+ fileutils (1.7.2)
46
+ i18n (1.14.1)
36
47
  concurrent-ruby (~> 1.0)
37
- jmespath (1.4.0)
38
- language_server-protocol (3.16.0.3)
39
- listen (3.7.0)
48
+ jmespath (1.6.2)
49
+ json (2.7.1)
50
+ language_server-protocol (3.17.0.3)
51
+ listen (3.8.0)
40
52
  rb-fsevent (~> 0.10, >= 0.10.3)
41
53
  rb-inotify (~> 0.9, >= 0.9.10)
42
- minitest (5.14.4)
43
- parallel (1.21.0)
44
- parser (3.0.3.0)
54
+ logger (1.6.0)
55
+ minitest (5.20.0)
56
+ mutex_m (0.2.0)
57
+ parallel (1.24.0)
58
+ parser (3.2.2.4)
45
59
  ast (~> 2.4.1)
46
- rack (2.2.3)
47
- rainbow (3.0.0)
48
- rake (13.0.6)
49
- rb-fsevent (0.11.0)
60
+ racc
61
+ racc (1.7.3)
62
+ rack (3.0.8)
63
+ rainbow (3.1.1)
64
+ rake (13.1.0)
65
+ rb-fsevent (0.11.2)
50
66
  rb-inotify (0.10.1)
51
67
  ffi (~> 1.0)
52
- rbs (1.7.1)
53
- redis (4.5.1)
54
- regexp_parser (2.1.1)
55
- rexml (3.2.5)
56
- rspec (3.10.0)
57
- rspec-core (~> 3.10.0)
58
- rspec-expectations (~> 3.10.0)
59
- rspec-mocks (~> 3.10.0)
60
- rspec-core (3.10.1)
61
- rspec-support (~> 3.10.0)
62
- rspec-expectations (3.10.1)
68
+ rbs (3.4.1)
69
+ abbrev
70
+ redis-client (0.19.1)
71
+ connection_pool
72
+ regexp_parser (2.8.3)
73
+ rexml (3.2.6)
74
+ rspec (3.12.0)
75
+ rspec-core (~> 3.12.0)
76
+ rspec-expectations (~> 3.12.0)
77
+ rspec-mocks (~> 3.12.0)
78
+ rspec-core (3.12.2)
79
+ rspec-support (~> 3.12.0)
80
+ rspec-expectations (3.12.3)
63
81
  diff-lcs (>= 1.2.0, < 2.0)
64
- rspec-support (~> 3.10.0)
65
- rspec-mocks (3.10.2)
82
+ rspec-support (~> 3.12.0)
83
+ rspec-mocks (3.12.6)
66
84
  diff-lcs (>= 1.2.0, < 2.0)
67
- rspec-support (~> 3.10.0)
68
- rspec-support (3.10.3)
69
- rubocop (1.23.0)
85
+ rspec-support (~> 3.12.0)
86
+ rspec-support (3.12.1)
87
+ rubocop (1.59.0)
88
+ json (~> 2.3)
89
+ language_server-protocol (>= 3.17.0)
70
90
  parallel (~> 1.10)
71
- parser (>= 3.0.0.0)
91
+ parser (>= 3.2.2.4)
72
92
  rainbow (>= 2.2.2, < 4.0)
73
93
  regexp_parser (>= 1.8, < 3.0)
74
- rexml
75
- rubocop-ast (>= 1.12.0, < 2.0)
94
+ rexml (>= 3.2.5, < 4.0)
95
+ rubocop-ast (>= 1.30.0, < 2.0)
76
96
  ruby-progressbar (~> 1.7)
77
- unicode-display_width (>= 1.4.0, < 3.0)
78
- rubocop-ast (1.13.0)
79
- parser (>= 3.0.1.1)
97
+ unicode-display_width (>= 2.4.0, < 3.0)
98
+ rubocop-ast (1.30.0)
99
+ parser (>= 3.2.1.0)
100
+ rubocop-capybara (2.19.0)
101
+ rubocop (~> 1.41)
102
+ rubocop-factory_bot (2.24.0)
103
+ rubocop (~> 1.33)
104
+ rubocop-performance (1.20.1)
105
+ rubocop (>= 1.48.1, < 2.0)
106
+ rubocop-ast (>= 1.30.0, < 2.0)
80
107
  rubocop-rake (0.6.0)
81
108
  rubocop (~> 1.0)
82
- rubocop-rspec (2.6.0)
83
- rubocop (~> 1.19)
84
- ruby-progressbar (1.11.0)
85
- sidekiq (6.3.1)
86
- connection_pool (>= 2.2.2)
87
- rack (~> 2.0)
88
- redis (>= 4.2.0)
89
- simplecov (0.21.2)
109
+ rubocop-rspec (2.25.0)
110
+ rubocop (~> 1.40)
111
+ rubocop-capybara (~> 2.17)
112
+ rubocop-factory_bot (~> 2.22)
113
+ rubocop-thread_safety (0.5.1)
114
+ rubocop (>= 0.90.0)
115
+ ruby-progressbar (1.13.0)
116
+ ruby2_keywords (0.0.5)
117
+ securerandom (0.3.1)
118
+ sidekiq (7.2.0)
119
+ concurrent-ruby (< 2)
120
+ connection_pool (>= 2.3.0)
121
+ rack (>= 2.2.4)
122
+ redis-client (>= 0.14.0)
123
+ simplecov (0.22.0)
90
124
  docile (~> 1.1)
91
125
  simplecov-html (~> 0.11)
92
126
  simplecov_json_formatter (~> 0.1)
93
127
  simplecov-html (0.12.3)
94
- simplecov_json_formatter (0.1.3)
95
- steep (0.46.0)
128
+ simplecov_json_formatter (0.1.4)
129
+ steep (1.6.0)
96
130
  activesupport (>= 5.1)
131
+ concurrent-ruby (>= 1.1.10)
132
+ csv (>= 3.0.9)
133
+ fileutils (>= 1.1.0)
134
+ json (>= 2.1.0)
97
135
  language_server-protocol (>= 3.15, < 4.0)
98
136
  listen (~> 3.0)
99
- parallel (>= 1.0.0)
100
- parser (>= 3.0)
137
+ logger (>= 1.3.0)
138
+ parser (>= 3.1)
101
139
  rainbow (>= 2.2.2, < 4.0)
102
- rbs (>= 1.2.0)
140
+ rbs (>= 3.1.0)
141
+ securerandom (>= 0.1)
142
+ strscan (>= 1.0.0)
103
143
  terminal-table (>= 2, < 4)
144
+ strscan (3.0.7)
104
145
  terminal-table (3.0.2)
105
146
  unicode-display_width (>= 1.1.1, < 3)
106
- tzinfo (2.0.4)
147
+ tzinfo (2.0.6)
107
148
  concurrent-ruby (~> 1.0)
108
- unicode-display_width (2.1.0)
109
- yard (0.9.26)
110
- zeitwerk (2.5.1)
149
+ unicode-display_width (2.5.0)
150
+ yard (0.9.34)
111
151
 
112
152
  PLATFORMS
153
+ aarch64-linux
154
+ arm64-darwin-21
113
155
  x86_64-darwin-19
114
156
  x86_64-linux
115
157
 
@@ -117,12 +159,14 @@ DEPENDENCIES
117
159
  rake
118
160
  rspec
119
161
  rubocop
162
+ rubocop-performance
120
163
  rubocop-rake
121
164
  rubocop-rspec
165
+ rubocop-thread_safety
122
166
  sidekiq-ecs-scaler!
123
167
  simplecov
124
168
  steep
125
169
  yard
126
170
 
127
171
  BUNDLED WITH
128
- 2.2.32
172
+ 2.4.10
data/README.md CHANGED
@@ -18,34 +18,33 @@ And then execute:
18
18
 
19
19
  ## Usage
20
20
 
21
- ### Configuration
21
+ ### Create Worker Class
22
22
 
23
23
  ```ruby
24
- SidekiqEcsScaler.configure do |config|
25
- # enable / disable of scaler, default is true
26
- config.enabled = true
24
+ # frozen_string_literal: true
27
25
 
28
- # logger, default is Sidekiq.logger
29
- config.logger = Sidekiq.logger
26
+ class SidekiqEcsScaleWorker
27
+ include Sidekiq::Worker
30
28
 
31
- # queue to monitor latency, default is "default"
32
- config.queue_name = "default"
33
-
34
- # minimum number of tasks, default is 1
35
- config.min_count = 1
36
-
37
- # maximum number of tasks, default is 1
38
- config.max_count = 3
39
-
40
- # maximum latency(seconds), default is 3600
41
- config.max_latency = 3600
29
+ # @return [void]
30
+ def perform
31
+ SidekiqEcsScaler::Client.update_desired_count(
32
+ max_count: 3
33
+ )
34
+ end
35
+ end
36
+ ```
42
37
 
43
- # custom ECS Client, default is Aws::ECS::Client.new
44
- config.ecs_client = Aws::ECS::Client.new
38
+ Options
45
39
 
46
- # Set worker options for scaling
47
- config.sidekiq_options = { "retry" => true, "queue" => "scheduler" }
48
- end
40
+ ```yaml
41
+ logger: logger, default is Sidekiq.logger
42
+ queue_name: queue to monitor latency, default is "default"
43
+ min_count: minimum number of tasks, default is 1
44
+ max_count: maximum number of tasks, default is 1
45
+ step_count: steps number in the desired count range, default is 1
46
+ max_latency: maximum latency(seconds), default is 3600
47
+ ecs_client: custom ECS Client, default is Aws::ECS::Client.new
49
48
  ```
50
49
 
51
50
  ### With Sidekiq Scheduler
@@ -57,7 +56,7 @@ When using [sidekiq-scheduler](https://github.com/moove-it/sidekiq-scheduler), s
57
56
  # example
58
57
 
59
58
  :schedule:
60
- SidekiqEcsScaler::Worker:
59
+ SidekiqEcsScaleWorker:
61
60
  cron: "0 */15 * * * *"
62
61
  # It is safe to set this queue to have a higher priority than the monitored queue.
63
62
  queue: scheduler
data/Rakefile CHANGED
@@ -12,8 +12,11 @@ RuboCop::RakeTask.new(:lint) do |t|
12
12
  t.options = %w[--parallel]
13
13
  end
14
14
  namespace :lint do
15
- desc "Lint fix (Rubocop)"
16
- task fix: :auto_correct
15
+ desc "Lint with fix (Rubocop)"
16
+ task fix: :autocorrect
17
+
18
+ desc "Lint with unsafe fix (Rubocop)"
19
+ task fixall: :autocorrect_all
17
20
  end
18
21
 
19
22
  # steep
@@ -32,8 +35,12 @@ end
32
35
  require "yard"
33
36
  desc "document"
34
37
  task :doc do
35
- YARD::CLI::CommandParser.run
36
- `yard`.lines(chomp: true).last.match(/\d+/)[0].to_i == 100 || exit(1)
38
+ io = StringIO.new
39
+ YARD::Logger.instance(io)
40
+ YARD::CLI::CommandParser.run(*%w[stats --list-undoc])
41
+ result = io.tap(&:rewind).read
42
+ $stdout.puts(result)
43
+ result.lines(chomp: true).last.strip == "100.00% documented" || exit(1)
37
44
  end
38
45
 
39
46
  task default: %i[lint typecheck spec doc]
data/docker-compose.yml CHANGED
@@ -1,9 +1,9 @@
1
1
  version: "3"
2
2
 
3
3
  services:
4
- sidekiq-ecs-scaler:
4
+ gem:
5
5
  build:
6
6
  context: .
7
7
  volumes:
8
- - .:/usr/src/sidekiq-ecs-scaler
8
+ - .:/usr/src/gem
9
9
  command: /bin/bash
@@ -1,41 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "logger"
4
- require "uri"
5
- require "net/http"
6
- require "json"
7
- require "sidekiq"
8
- require "sidekiq/api"
9
- require "aws-sdk-ecs"
10
- require_relative "sidekiq-ecs-scaler/version"
11
- require_relative "sidekiq-ecs-scaler/task_meta_v4"
12
- require_relative "sidekiq-ecs-scaler/configuration"
13
- require_relative "sidekiq-ecs-scaler/client"
14
- require_relative "sidekiq-ecs-scaler/worker"
15
-
16
- # SidekiqEcsScaler
17
- module SidekiqEcsScaler
18
- # SidekiqEcsScaler::Error
19
- class Error < StandardError; end
20
-
21
- class << self
22
- # @return [SidekiqEcsScaler::Configuration]
23
- def config
24
- @config ||= Configuration.new
25
- end
26
-
27
- # @yieldparam config [SidekiqEcsScaler::Configuration]
28
- # @yieldreturn [void]
29
- # @return [void]
30
- def configure
31
- raise Error, "No block is given!" unless block_given?
32
-
33
- yield config
34
- end
35
-
36
- # @return [SidekiqEcsScaler::Client]
37
- def client
38
- Client.new(config)
39
- end
40
- end
41
- end
3
+ require "sidekiq_ecs_scaler"
@@ -3,16 +3,22 @@
3
3
  module SidekiqEcsScaler
4
4
  # SidekiqEcsScaler::Client
5
5
  class Client
6
+ class << self
7
+ # @param keywords [Hash]
8
+ # @return [Integer]
9
+ def update_desired_count(**keywords)
10
+ new(SidekiqEcsScaler::Configuration.new(**keywords)).update_desired_count
11
+ end
12
+ end
13
+
6
14
  # @param config [SidekiqEcsScaler::Configuration]
7
15
  # @return [void]
8
16
  def initialize(config)
9
17
  @config = config
10
18
  end
11
19
 
12
- # @return [Integer, nil]
20
+ # @return [Integer]
13
21
  def update_desired_count
14
- return if !config.enabled || config.task_meta.nil?
15
-
16
22
  desired_count = desired_count_by_latency
17
23
  service = describe_service
18
24
 
@@ -39,26 +45,28 @@ module SidekiqEcsScaler
39
45
 
40
46
  # @return [Integer]
41
47
  def desired_count_by_latency
42
- (config.min_count..config.max_count).to_a.at(
43
- (queue_latency.to_f / config.latency_per_count).floor.to_i
44
- ) || config.max_count
48
+ desired_count_list.at((queue_latency.to_f / config.latency_per_step_count).floor.to_i) || config.max_count
49
+ end
50
+
51
+ # @return [Array<Integer>]
52
+ def desired_count_list
53
+ config.min_count.step(config.max_count, config.step_count).to_a
45
54
  end
46
55
 
47
56
  # @return [String]
48
- def service_name
49
- config.task_meta!.then do |task_meta|
50
- config.ecs_client.describe_tasks(
51
- { cluster: task_meta.cluster, tasks: [task_meta.task_arn] }
52
- ).tasks.first&.then { |task| task.group.delete_prefix("service:") } || (
53
- raise Error, "Task(#{task_meta.task_arn}) does not exist in cluster!"
54
- )
55
- end
57
+ def describe_service_name
58
+ task_meta = config.task_meta
59
+ task = config.ecs_client.describe_tasks({ cluster: task_meta.cluster, tasks: [task_meta.task_arn] }).tasks.first
60
+ raise Error, "Task(#{task_meta.task_arn}) does not exist in cluster!" if task.nil?
61
+
62
+ task.group.delete_prefix("service:")
56
63
  end
57
64
 
58
65
  # @return [Aws::ECS::Types::Service]
59
66
  def describe_service
67
+ service_name = describe_service_name
60
68
  config.ecs_client.describe_services(
61
- { cluster: config.task_meta!.cluster, services: [service_name] }
69
+ { cluster: config.task_meta.cluster, services: [service_name] }
62
70
  ).services.first || (raise Error, "Service(#{service_name}) does not exist in cluster!")
63
71
  end
64
72
 
@@ -67,11 +75,7 @@ module SidekiqEcsScaler
67
75
  # @return [Aws::ECS::Types::UpdateServiceResponse]
68
76
  def update_service(service:, desired_count:)
69
77
  config.ecs_client.update_service(
70
- {
71
- cluster: service.cluster_arn,
72
- service: service.service_name,
73
- desired_count: desired_count
74
- }
78
+ { cluster: service.cluster_arn, service: service.service_name, desired_count: desired_count }
75
79
  )
76
80
  end
77
81
 
@@ -3,9 +3,6 @@
3
3
  module SidekiqEcsScaler
4
4
  # SidekiqEcsScaler::Configuration
5
5
  class Configuration
6
- # @!attribute [r] enabled
7
- # @return [Boolean]
8
- attr_reader :enabled
9
6
  # @!attribute [r] queue_name
10
7
  # @return [String]
11
8
  attr_reader :queue_name
@@ -15,36 +12,59 @@ module SidekiqEcsScaler
15
12
  # @!attribute [r] max_count
16
13
  # @return [Integer]
17
14
  attr_reader :max_count
15
+ # @!attribute [r] step_count
16
+ # @return [Integer]
17
+ attr_reader :step_count
18
18
  # @!attribute [r] max_latency
19
19
  # @return [Integer]
20
20
  attr_reader :max_latency
21
21
  # @!attribute [r] task_meta
22
- # @return [SidekiqEcsScaler::TaskMetaV4, nil]
22
+ # @return [SidekiqEcsScaler::TaskMetaV4]
23
23
  attr_reader :task_meta
24
+ # @!attribute [r] ecs_client
25
+ # @return [Aws::Ecs::Client]
26
+ attr_reader :ecs_client
27
+ # @!attribute [r] logger
28
+ # @return [Logger]
29
+ attr_reader :logger
24
30
 
31
+ # @param queue_name [String]
32
+ # @param min_count [Integer]
33
+ # @param max_count [Integer]
34
+ # @param step_count [Integer]
35
+ # @param max_latency [Integer]
36
+ # @param task_meta [SidekiqEcsScaler::TaskMetaV4]
37
+ # @param ecs_client [Aws::ECS::Client]
38
+ # @param logger [Logger]
25
39
  # @return [void]
26
- def initialize
27
- @queue_name = "default"
28
- @min_count = 1
29
- @max_count = 1
30
- @max_latency = 3600
31
- @task_meta = TaskMetaV4.build_or_null
32
- @enabled = true
40
+ def initialize( # rubocop:disable Metrics/ParameterLists
41
+ queue_name: "default",
42
+ min_count: 1,
43
+ max_count: 1,
44
+ step_count: 1,
45
+ max_latency: 3_600,
46
+ task_meta: TaskMetaV4.build_or_null,
47
+ ecs_client: Aws::ECS::Client.new,
48
+ logger: Sidekiq.logger
49
+ )
50
+ self.queue_name = queue_name
51
+ self.min_count = min_count
52
+ self.max_count = max_count
53
+ self.step_count = step_count
54
+ self.max_latency = max_latency
55
+ self.task_meta = task_meta
56
+ self.ecs_client = ecs_client
57
+ self.logger = logger
33
58
  end
34
59
 
35
- # @param enabled [Boolean]
36
- # @return [void]
37
- # @raise [ArgumentError]
38
- def enabled=(enabled)
39
- raise ArgumentError if !enabled.is_a?(TrueClass) && !enabled.is_a?(FalseClass)
40
-
41
- @enabled = enabled
60
+ # @return [Integer]
61
+ def latency_per_step_count
62
+ (max_latency / ((1 + max_count - min_count).to_f / step_count).ceil).tap do |value|
63
+ value.positive? || (raise Error, "latency per count isn't positive!")
64
+ end
42
65
  end
43
66
 
44
- # @return [Logger]
45
- def logger
46
- @logger ||= Sidekiq.logger
47
- end
67
+ private
48
68
 
49
69
  # @param logger [Logger]
50
70
  # @return [void]
@@ -66,22 +86,30 @@ module SidekiqEcsScaler
66
86
  # @return [void]
67
87
  # @raise [ArgumentError]
68
88
  def min_count=(min_count)
69
- raise ArgumentError unless min_count.positive?
89
+ assert_positive_number!(min_count)
70
90
 
71
91
  @min_count = min_count
72
- @max_count = min_count if min_count > max_count
73
92
  end
74
93
 
75
94
  # @param max_count [Integer]
76
95
  # @return [void]
77
96
  # @raise [ArgumentError]
78
97
  def max_count=(max_count)
79
- raise ArgumentError unless max_count.positive?
98
+ assert_positive_number!(max_count)
80
99
 
81
100
  @max_count = max_count
82
101
  @min_count = max_count if max_count < min_count
83
102
  end
84
103
 
104
+ # @param step_count [Integer]
105
+ # @return [void]
106
+ # @raise [ArgumentError]
107
+ def step_count=(step_count)
108
+ assert_positive_number!(step_count)
109
+
110
+ @step_count = step_count
111
+ end
112
+
85
113
  # @param max_latency [Integer]
86
114
  # @return [void]
87
115
  # @raise [ArgumentError]
@@ -91,11 +119,6 @@ module SidekiqEcsScaler
91
119
  @max_latency = max_latency
92
120
  end
93
121
 
94
- # @return [Aws::ECS::Client]
95
- def ecs_client
96
- @ecs_client ||= Aws::ECS::Client.new
97
- end
98
-
99
122
  # @param ecs_client [Aws::ECS::Client]
100
123
  # @return [void]
101
124
  # @raise [ArgumentError]
@@ -105,29 +128,20 @@ module SidekiqEcsScaler
105
128
  @ecs_client = ecs_client
106
129
  end
107
130
 
108
- # @return [Integer]
109
- def latency_per_count
110
- (max_latency / (1 + max_count - min_count)).tap do |value|
111
- value.positive? || (raise Error, "latency per count isn't positive!")
112
- end
113
- end
114
-
115
- # @return [SidekiqEcsScaler::TaskMetaV4]
116
- def task_meta!
117
- task_meta || (raise Error, "task metadata is null!")
118
- end
131
+ # @param task_meta [SidekiqEcsScaler::TaskMetaV4]
132
+ # @return [void]
133
+ # @raise [ArgumentError]
134
+ def task_meta=(task_meta)
135
+ raise ArgumentError unless task_meta.is_a?(SidekiqEcsScaler::TaskMetaV4)
119
136
 
120
- # @return [Hash]
121
- def sidekiq_options
122
- ::SidekiqEcsScaler::Worker.sidekiq_options
137
+ @task_meta = task_meta
123
138
  end
124
139
 
125
- # @param sidekiq_options [Hash]
140
+ # @param number [Integer]
126
141
  # @return [void]
127
- def sidekiq_options=(sidekiq_options)
128
- raise ArgumentError unless sidekiq_options.is_a?(Hash)
129
-
130
- ::SidekiqEcsScaler::Worker.sidekiq_options(sidekiq_options)
142
+ # @raise [ArgumentError]
143
+ def assert_positive_number!(number)
144
+ raise ArgumentError unless number.positive?
131
145
  end
132
146
  end
133
147
  end
@@ -11,7 +11,8 @@ module SidekiqEcsScaler
11
11
  # @return [SidekiqEcsScaler::TaskMetaV4, nil]
12
12
  def build_or_null
13
13
  ENV.fetch("ECS_CONTAINER_METADATA_URI_V4", nil)&.then do |uri|
14
- new(JSON.parse(Net::HTTP.get(URI.parse("#{uri}/task"))))
14
+ resp = JSON.parse(Net::HTTP.get(URI.parse("#{uri}/task")))
15
+ new(cluster: resp.fetch("Cluster"), task_arn: resp.fetch("TaskARN"))
15
16
  end
16
17
  rescue StandardError
17
18
  nil
@@ -25,11 +26,12 @@ module SidekiqEcsScaler
25
26
  # @return [String]
26
27
  attr_reader :task_arn
27
28
 
28
- # @param resp [Hash]
29
+ # @param cluster [String]
30
+ # @param task_arn [String]
29
31
  # @return [void]
30
- def initialize(resp)
31
- @cluster = resp.fetch("Cluster")
32
- @task_arn = resp.fetch("TaskARN")
32
+ def initialize(cluster:, task_arn:)
33
+ @cluster = cluster
34
+ @task_arn = task_arn
33
35
  end
34
36
  end
35
37
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module SidekiqEcsScaler
4
4
  # @return [String]
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+ require "uri"
5
+ require "net/http"
6
+ require "json"
7
+ require "sidekiq"
8
+ require "sidekiq/api"
9
+ require "aws-sdk-ecs"
10
+ require_relative "sidekiq_ecs_scaler/version"
11
+ require_relative "sidekiq_ecs_scaler/task_meta_v4"
12
+ require_relative "sidekiq_ecs_scaler/configuration"
13
+ require_relative "sidekiq_ecs_scaler/client"
14
+
15
+ # SidekiqEcsScaler
16
+ module SidekiqEcsScaler
17
+ # SidekiqEcsScaler::Error
18
+ class Error < StandardError; end
19
+ end
@@ -0,0 +1,76 @@
1
+ ---
2
+ path: ".gem_rbs_collection"
3
+ gems:
4
+ - name: aws-sdk-core
5
+ version: '3'
6
+ source:
7
+ type: git
8
+ name: ruby/gem_rbs_collection
9
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
10
+ remote: https://github.com/ruby/gem_rbs_collection.git
11
+ repo_dir: gems
12
+ - name: cgi
13
+ version: '0'
14
+ source:
15
+ type: stdlib
16
+ - name: concurrent-ruby
17
+ version: '1.1'
18
+ source:
19
+ type: git
20
+ name: ruby/gem_rbs_collection
21
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
22
+ remote: https://github.com/ruby/gem_rbs_collection.git
23
+ repo_dir: gems
24
+ - name: connection_pool
25
+ version: '2.4'
26
+ source:
27
+ type: git
28
+ name: ruby/gem_rbs_collection
29
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
30
+ remote: https://github.com/ruby/gem_rbs_collection.git
31
+ repo_dir: gems
32
+ - name: logger
33
+ version: '0'
34
+ source:
35
+ type: stdlib
36
+ - name: monitor
37
+ version: '0'
38
+ source:
39
+ type: stdlib
40
+ - name: rack
41
+ version: '2.2'
42
+ source:
43
+ type: git
44
+ name: ruby/gem_rbs_collection
45
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
46
+ remote: https://github.com/ruby/gem_rbs_collection.git
47
+ repo_dir: gems
48
+ - name: redis
49
+ version: '4.2'
50
+ source:
51
+ type: git
52
+ name: ruby/gem_rbs_collection
53
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
54
+ remote: https://github.com/ruby/gem_rbs_collection.git
55
+ repo_dir: gems
56
+ - name: sidekiq
57
+ version: '6.3'
58
+ source:
59
+ type: git
60
+ name: ruby/gem_rbs_collection
61
+ revision: 13ae8cd19056d62358a9d4836106b8b31219fc1e
62
+ remote: https://github.com/ruby/gem_rbs_collection.git
63
+ repo_dir: gems
64
+ - name: tempfile
65
+ version: '0'
66
+ source:
67
+ type: stdlib
68
+ - name: timeout
69
+ version: '0'
70
+ source:
71
+ type: stdlib
72
+ - name: uri
73
+ version: '0'
74
+ source:
75
+ type: stdlib
76
+ gemfile_lock_path: Gemfile.lock
@@ -0,0 +1,17 @@
1
+ # Download sources
2
+ sources:
3
+ - type: git
4
+ name: ruby/gem_rbs_collection
5
+ remote: https://github.com/ruby/gem_rbs_collection.git
6
+ revision: main
7
+ repo_dir: gems
8
+
9
+ # You can specify local directories as sources also.
10
+ # - type: local
11
+ # path: path/to/your/local/repository
12
+
13
+ # A directory to install the downloaded RBSs
14
+ path: .gem_rbs_collection
15
+
16
+ gems:
17
+ - name: redis
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/sidekiq-ecs-scaler/version"
3
+ require_relative "lib/sidekiq_ecs_scaler/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "sidekiq-ecs-scaler"
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = ["lib"]
31
31
 
32
32
  spec.add_dependency "aws-sdk-ecs", "> 1", "< 2"
33
- spec.add_dependency "sidekiq", "> 5", "< 7"
33
+ spec.add_dependency "sidekiq", "> 5", "< 8"
34
34
 
35
35
  # For more information and examples about making a new gem, checkout our
36
36
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -4,16 +4,12 @@ module SidekiqEcsScaler
4
4
  class Error < StandardError
5
5
  end
6
6
 
7
- def self.config: () -> ::SidekiqEcsScaler::Configuration
8
-
9
- def self.configure: () { (::SidekiqEcsScaler::Configuration) -> void } -> void
10
-
11
- def self.client: () -> ::SidekiqEcsScaler::Client
12
-
13
7
  class Client
8
+ def self.update_desired_count: (**untyped) -> ::Integer
9
+
14
10
  def initialize: (::SidekiqEcsScaler::Configuration) -> void
15
11
 
16
- def update_desired_count: () -> ::Integer?
12
+ def update_desired_count: () -> ::Integer
17
13
 
18
14
  private
19
15
 
@@ -23,7 +19,9 @@ module SidekiqEcsScaler
23
19
 
24
20
  def desired_count_by_latency: () -> ::Integer
25
21
 
26
- def service_name: () -> ::String
22
+ def desired_count_list: () -> ::Array[::Integer]
23
+
24
+ def describe_service_name: () -> ::String
27
25
 
28
26
  def describe_service: () -> ::Aws::ECS::Types::Service
29
27
 
@@ -35,43 +33,54 @@ module SidekiqEcsScaler
35
33
  end
36
34
 
37
35
  class Configuration
38
- attr_reader enabled: bool
39
-
40
- attr_accessor queue_name: ::String
36
+ attr_reader queue_name: ::String
41
37
 
42
38
  attr_reader min_count: ::Integer
43
39
 
44
40
  attr_reader max_count: ::Integer
45
41
 
42
+ attr_reader step_count: ::Integer
43
+
46
44
  attr_reader max_latency: ::Integer
47
45
 
48
- attr_reader task_meta: ::SidekiqEcsScaler::TaskMetaV4?
46
+ attr_reader task_meta: ::SidekiqEcsScaler::TaskMetaV4
47
+
48
+ attr_reader logger: ::Logger
49
+
50
+ attr_reader ecs_client: ::Aws::ECS::Client
49
51
 
50
- def initialize: () -> void
52
+ def initialize: (
53
+ ?queue_name: ::String,
54
+ ?min_count: ::Integer,
55
+ ?max_count: ::Integer,
56
+ ?step_count: ::Integer,
57
+ ?max_latency: ::Integer,
58
+ ?task_meta: ::SidekiqEcsScaler::TaskMetaV4,
59
+ ?ecs_client: ::Aws::ECS::Client,
60
+ ?logger: ::Logger
61
+ ) -> void
51
62
 
52
- def enabled=: (bool) -> void
63
+ def latency_per_step_count: () -> ::Integer
64
+
65
+ private
53
66
 
54
- def logger: () -> ::Logger
67
+ def assert_positive_number!: (::Integer) -> void
55
68
 
56
69
  def logger=: (::Logger) -> void
57
70
 
71
+ def queue_name=: (::String) -> void
72
+
58
73
  def min_count=: (::Integer) -> void
59
74
 
60
75
  def max_count=: (::Integer) -> void
61
76
 
77
+ def step_count=: (::Integer) -> void
78
+
62
79
  def max_latency=: (::Integer) -> void
63
80
 
64
- def ecs_client: () -> ::Aws::ECS::Client
81
+ def task_meta=: (::SidekiqEcsScaler::TaskMetaV4) -> void
65
82
 
66
83
  def ecs_client=: (::Aws::ECS::Client) -> void
67
-
68
- def latency_per_count: () -> ::Integer
69
-
70
- def task_meta!: () -> ::SidekiqEcsScaler::TaskMetaV4
71
-
72
- def sidekiq_options: () -> ::Hash[untyped, untyped]
73
-
74
- def sidekiq_options=: (::Hash[untyped, untyped]) -> void
75
84
  end
76
85
 
77
86
  class TaskMetaV4
@@ -81,14 +90,6 @@ module SidekiqEcsScaler
81
90
 
82
91
  attr_reader task_arn: ::String
83
92
 
84
- def initialize: (::Hash[untyped, untyped]) -> void
85
- end
86
-
87
- class Worker
88
- include ::Sidekiq::Worker
89
-
90
- def self.sidekiq_options: (?::Hash[untyped, untyped]) -> ::Hash[untyped, untyped]
91
-
92
- def perform: () -> ::Integer?
93
+ def initialize: (cluster: ::String, task_arn: ::String) -> void
93
94
  end
94
95
  end
data/sig-private/uri.rbs CHANGED
@@ -1,5 +1,6 @@
1
1
  module ::URI
2
2
  def self.parse: (String) -> ::URI::HTTP
3
+ | ...
3
4
 
4
5
  class ::URI::HTTP
5
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-ecs-scaler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shoma07
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-30 00:00:00.000000000 Z
11
+ date: 2024-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-ecs
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '5'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '7'
42
+ version: '8'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: '5'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '7'
52
+ version: '8'
53
53
  description: auto scaler of sidekiq worker deploymented to aws ecs
54
54
  email:
55
55
  - 23730734+shoma07@users.noreply.github.com
@@ -74,15 +74,16 @@ files:
74
74
  - docker-compose.yml
75
75
  - exe/sidekiq-ecs-scaler
76
76
  - lib/sidekiq-ecs-scaler.rb
77
- - lib/sidekiq-ecs-scaler/client.rb
78
- - lib/sidekiq-ecs-scaler/configuration.rb
79
- - lib/sidekiq-ecs-scaler/task_meta_v4.rb
80
- - lib/sidekiq-ecs-scaler/version.rb
81
- - lib/sidekiq-ecs-scaler/worker.rb
77
+ - lib/sidekiq_ecs_scaler.rb
78
+ - lib/sidekiq_ecs_scaler/client.rb
79
+ - lib/sidekiq_ecs_scaler/configuration.rb
80
+ - lib/sidekiq_ecs_scaler/task_meta_v4.rb
81
+ - lib/sidekiq_ecs_scaler/version.rb
82
+ - rbs_collection.lock.yaml
83
+ - rbs_collection.yaml
82
84
  - sidekiq-ecs-scaler.gemspec
83
85
  - sig-private/aws-sdk-ecs.rbs
84
86
  - sig-private/net/http.rbs
85
- - sig-private/sidekiq.rbs
86
87
  - sig-private/uri.rbs
87
88
  - sig/sidekiq-ecs-scaler.rbs
88
89
  homepage: https://github.com/shoma07/sidekiq-ecs-scaler
@@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
106
  - !ruby/object:Gem::Version
106
107
  version: '0'
107
108
  requirements: []
108
- rubygems_version: 3.2.32
109
+ rubygems_version: 3.4.10
109
110
  signing_key:
110
111
  specification_version: 4
111
112
  summary: auto scaler of sidekiq worker deploymented to aws ecs
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SidekiqEcsScaler
4
- # SidekiqEcsScaler::Worker
5
- class Worker
6
- include Sidekiq::Worker
7
-
8
- # @return [Integer, nil]
9
- def perform
10
- SidekiqEcsScaler.client.update_desired_count
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module Sidekiq
2
- def self.logger: () -> ::Logger
3
-
4
- module Worker
5
- def self.sidekiq_options: (?::Hash[untyped, untyped]) -> ::Hash[untyped, untyped]
6
- end
7
-
8
- class Queue
9
- def initialize: (::String) -> void
10
-
11
- def latency: () -> ::Float
12
- end
13
- end