sidekiq-ecs-scaler 0.2.0 → 0.3.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.
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