capistrano-asg-rolling 0.7.0 → 0.8.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: cceded2d7adcb767bc8bb432781055a91af8268303514564a4c1de86ccb2ac2e
4
- data.tar.gz: 8d08579c0a00000bb2457348e9808758d10d74751a08f7071e50fa794fb1ea72
3
+ metadata.gz: b336d65bcb11063bb59bd4934158b9cda2f3e03613442800d135d1bed513e208
4
+ data.tar.gz: 1bd33673762478806487a3d10f16662e9909bfbdf9edd21841b4db9de5ded2b5
5
5
  SHA512:
6
- metadata.gz: 964743e3ab4ad9813100f3968e45b044d80fc46d6e9141a85b07686b0b4566f8c12bb79f3614fa5d473b358782d3c002d03532f72b60440b666423c4bc5e4947
7
- data.tar.gz: 3366b9a2268485d777a101d1f29335aba073979122347c48e3191f318188ed3ce41eb2f3ec39861b286fa4a0148f9632af23b1d57f93f4e1d857f8f742e929b8
6
+ metadata.gz: f013f9d109849878be032295ab1c518e7e0f7617d32fadc6c3c71bf3da03d8cf57d0fd28f4260e4047ed91c424573b32341e8d4ecc22c6544aa8147da05c3f89
7
+ data.tar.gz: d0f61692e322b744772d463825044746ac57224b6dbf2c61e1ca85ced9efa09fbae18dc9f26690be9d2f8d82a768d701b9e1bbc024c50a5b4afe5636ee8d51cd
data/CODE_OF_CONDUCT.md CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at peter.postma@kentaa.nl. All
58
+ reported by contacting the project team at tech-arnhem@iraiser.eu. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano-asg-rolling (0.7.0)
4
+ capistrano-asg-rolling (0.8.0)
5
5
  aws-sdk-autoscaling (~> 1, >= 1.100.0)
6
6
  aws-sdk-ec2 (~> 1)
7
7
  capistrano (~> 3)
@@ -10,17 +10,17 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- addressable (2.8.8)
13
+ addressable (2.9.0)
14
14
  public_suffix (>= 2.0.2, < 8.0)
15
- airbrussh (1.6.0)
15
+ airbrussh (1.6.1)
16
16
  sshkit (>= 1.6.1, != 1.7.0)
17
17
  ast (2.4.3)
18
18
  aws-eventstream (1.4.0)
19
- aws-partitions (1.1198.0)
20
- aws-sdk-autoscaling (1.149.0)
21
- aws-sdk-core (~> 3, >= 3.239.1)
19
+ aws-partitions (1.1250.0)
20
+ aws-sdk-autoscaling (1.158.0)
21
+ aws-sdk-core (~> 3, >= 3.247.0)
22
22
  aws-sigv4 (~> 1.5)
23
- aws-sdk-core (3.240.0)
23
+ aws-sdk-core (3.247.0)
24
24
  aws-eventstream (~> 1, >= 1.3.0)
25
25
  aws-partitions (~> 1, >= 1.992.0)
26
26
  aws-sigv4 (~> 1.9)
@@ -28,14 +28,14 @@ GEM
28
28
  bigdecimal
29
29
  jmespath (~> 1, >= 1.6.1)
30
30
  logger
31
- aws-sdk-ec2 (1.587.0)
32
- aws-sdk-core (~> 3, >= 3.239.1)
31
+ aws-sdk-ec2 (1.617.0)
32
+ aws-sdk-core (~> 3, >= 3.247.0)
33
33
  aws-sigv4 (~> 1.5)
34
34
  aws-sigv4 (1.12.1)
35
35
  aws-eventstream (~> 1, >= 1.0.2)
36
36
  base64 (0.3.0)
37
- bigdecimal (4.0.1)
38
- capistrano (3.20.0)
37
+ bigdecimal (4.1.2)
38
+ capistrano (3.20.1)
39
39
  airbrussh (>= 1.0.0)
40
40
  i18n
41
41
  rake (>= 10.0.0)
@@ -45,11 +45,12 @@ GEM
45
45
  bigdecimal
46
46
  rexml
47
47
  diff-lcs (1.6.2)
48
+ docile (1.4.1)
48
49
  hashdiff (1.2.1)
49
50
  i18n (1.14.8)
50
51
  concurrent-ruby (~> 1.0)
51
52
  jmespath (1.6.2)
52
- json (2.18.0)
53
+ json (2.19.5)
53
54
  language_server-protocol (3.17.0.5)
54
55
  lint_roller (1.1.0)
55
56
  logger (1.7.0)
@@ -57,18 +58,18 @@ GEM
57
58
  net-ssh (>= 2.6.5, < 8.0.0)
58
59
  net-sftp (4.0.0)
59
60
  net-ssh (>= 5.0.0, < 8.0.0)
60
- net-ssh (7.3.0)
61
+ net-ssh (7.3.2)
61
62
  ostruct (0.6.3)
62
- parallel (1.27.0)
63
- parser (3.3.10.0)
63
+ parallel (1.28.0)
64
+ parser (3.3.11.1)
64
65
  ast (~> 2.4.1)
65
66
  racc
66
- prism (1.7.0)
67
+ prism (1.9.0)
67
68
  public_suffix (6.0.2)
68
69
  racc (1.8.1)
69
70
  rainbow (3.1.1)
70
- rake (13.3.1)
71
- regexp_parser (2.11.3)
71
+ rake (13.4.2)
72
+ regexp_parser (2.12.0)
72
73
  rexml (3.4.4)
73
74
  rspec (3.13.2)
74
75
  rspec-core (~> 3.13.0)
@@ -79,24 +80,24 @@ GEM
79
80
  rspec-expectations (3.13.5)
80
81
  diff-lcs (>= 1.2.0, < 2.0)
81
82
  rspec-support (~> 3.13.0)
82
- rspec-mocks (3.13.7)
83
+ rspec-mocks (3.13.8)
83
84
  diff-lcs (>= 1.2.0, < 2.0)
84
85
  rspec-support (~> 3.13.0)
85
- rspec-support (3.13.6)
86
- rubocop (1.82.0)
86
+ rspec-support (3.13.7)
87
+ rubocop (1.86.2)
87
88
  json (~> 2.3)
88
89
  language_server-protocol (~> 3.17.0.2)
89
90
  lint_roller (~> 1.1.0)
90
- parallel (~> 1.10)
91
+ parallel (>= 1.10)
91
92
  parser (>= 3.3.0.2)
92
93
  rainbow (>= 2.2.2, < 4.0)
93
94
  regexp_parser (>= 2.9.3, < 3.0)
94
- rubocop-ast (>= 1.48.0, < 2.0)
95
+ rubocop-ast (>= 1.49.0, < 2.0)
95
96
  ruby-progressbar (~> 1.7)
96
97
  unicode-display_width (>= 2.4.0, < 4.0)
97
- rubocop-ast (1.48.0)
98
+ rubocop-ast (1.49.1)
98
99
  parser (>= 3.3.7.2)
99
- prism (~> 1.4)
100
+ prism (~> 1.7)
100
101
  rubocop-performance (1.26.1)
101
102
  lint_roller (~> 1.1)
102
103
  rubocop (>= 1.75.0, < 2.0)
@@ -104,10 +105,16 @@ GEM
104
105
  rubocop-rake (0.7.1)
105
106
  lint_roller (~> 1.1)
106
107
  rubocop (>= 1.72.1)
107
- rubocop-rspec (3.8.0)
108
+ rubocop-rspec (3.9.0)
108
109
  lint_roller (~> 1.1)
109
110
  rubocop (~> 1.81)
110
111
  ruby-progressbar (1.13.0)
112
+ simplecov (0.22.0)
113
+ docile (~> 1.1)
114
+ simplecov-html (~> 0.11)
115
+ simplecov_json_formatter (~> 0.1)
116
+ simplecov-html (0.13.2)
117
+ simplecov_json_formatter (0.1.4)
111
118
  sshkit (1.25.0)
112
119
  base64
113
120
  logger
@@ -118,7 +125,7 @@ GEM
118
125
  unicode-display_width (3.2.0)
119
126
  unicode-emoji (~> 4.1)
120
127
  unicode-emoji (4.2.0)
121
- webmock (3.26.1)
128
+ webmock (3.26.2)
122
129
  addressable (>= 2.8.0)
123
130
  crack (>= 0.3.2)
124
131
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -135,6 +142,7 @@ DEPENDENCIES
135
142
  rubocop-performance (~> 1.20)
136
143
  rubocop-rake (~> 0.6)
137
144
  rubocop-rspec (~> 3.0)
145
+ simplecov (~> 0.22)
138
146
  webmock (~> 3.11)
139
147
 
140
148
  BUNDLED WITH
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021 Kentaa BV
3
+ Copyright (c) 2025 Kentaa BV
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -113,6 +113,22 @@ Enable or disable auto-rollback on instance refreshes (default: false):
113
113
  set :asg_instance_refresh_auto_rollback, true
114
114
  ```
115
115
 
116
+ The AWS clients are configured with `adaptive` retry mode and a retry limit of 10 by default, so transient throttling (`Aws::AutoScaling::Errors::Throttling: Rate exceeded`) does not abort a deployment. You can tune both:
117
+
118
+ ```ruby
119
+ # config/deploy.rb
120
+ set :asg_aws_retry_mode, 'adaptive' # default; one of 'legacy', 'standard', 'adaptive'
121
+ set :asg_aws_retry_limit, 10 # default
122
+ ```
123
+
124
+ After creating an AMI, the gem waits until it becomes available before triggering an instance refresh. The defaults match the AWS SDK defaults (~10 minutes), but for larger root volumes (e.g. resizing 24 GB → 32 GB) the AMI can take longer to become available. Override the waiter via:
125
+
126
+ ```ruby
127
+ # config/deploy.rb
128
+ set :asg_ami_wait_delay, 15 # seconds between polls (default: 15)
129
+ set :asg_ami_wait_max_attempts, 40 # max polls (default: 40, ≈ 10 minutes)
130
+ ```
131
+
116
132
  ## Usage
117
133
 
118
134
  Specify the Auto Scaling Groups with the keyword `autoscale` instead of using the `server` keyword in Capistrano's stage configuration. Provide the name of the Auto Scaling Group and any properties you want to pass to the server:
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'capistrano/asg/rolling/version'
3
+ require_relative 'lib/capistrano/asg/rolling/version'
6
4
 
7
5
  Gem::Specification.new do |spec|
8
6
  spec.name = 'capistrano-asg-rolling'
9
7
  spec.version = Capistrano::ASG::Rolling::VERSION
10
- spec.authors = ['Kentaa']
11
- spec.email = ['developers@kentaa.nl']
8
+ spec.authors = %w[Kentaa iRaiser]
9
+ spec.email = ['tech-arnhem@iraiser.eu']
12
10
 
13
11
  spec.summary = 'Capistrano plugin for performing rolling updates to AWS Auto Scaling Groups using Instance Refresh'
14
12
  spec.homepage = 'https://github.com/KentaaNL/capistrano-asg-rolling'
@@ -31,6 +29,7 @@ Gem::Specification.new do |spec|
31
29
  spec.add_development_dependency 'bundler', '~> 2.0'
32
30
  spec.add_development_dependency 'rake', '~> 13.0'
33
31
  spec.add_development_dependency 'rspec', '~> 3.0'
32
+ spec.add_development_dependency 'simplecov', '~> 0.22'
34
33
  spec.add_development_dependency 'webmock', '~> 3.11'
35
34
 
36
35
  spec.add_dependency 'aws-sdk-autoscaling', '~> 1', '>= 1.100.0'
@@ -36,10 +36,17 @@ module Capistrano
36
36
  response = aws_ec2_client.create_image(options)
37
37
 
38
38
  begin
39
- aws_ec2_client.wait_until(:image_available, image_ids: [response.image_id])
40
- rescue Aws::Waiters::Errors::TooManyAttemptsError
39
+ aws_ec2_client.wait_until(:image_available, image_ids: [response.image_id]) do |waiter|
40
+ waiter.delay = Configuration.ami_wait_delay
41
+ waiter.max_attempts = Configuration.ami_wait_max_attempts
42
+ end
43
+ rescue Aws::Waiters::Errors::TooManyAttemptsError => e
41
44
  # When waiting for the AMI takes longer than the default (10 minutes),
42
- # then assume it will eventually succeed and just continue.
45
+ # then assume it will eventually succeed and just continue. Surface a
46
+ # warning so operators can see that the wait did not complete in time
47
+ # (for example after increasing the root volume size of the source
48
+ # instance) before the subsequent Instance Refresh is started.
49
+ Kernel.warn("WARNING: timed out waiting for AMI #{response.image_id} to become available: #{e.message}")
43
50
  end
44
51
 
45
52
  new(response.image_id, instance)
@@ -81,7 +81,11 @@ module Capistrano
81
81
  auto_rollback: auto_rollback
82
82
  }.compact
83
83
  ).instance_refresh_id
84
- rescue Aws::AutoScaling::Errors::InstanceRefreshInProgress => e
84
+ rescue Aws::AutoScaling::Errors::ServiceError => e
85
+ # Wrap all AWS Auto Scaling service errors (InstanceRefreshInProgress,
86
+ # ValidationError, throttling, etc.) so the rake task can rescue a
87
+ # single gem-defined error type and continue with the remaining
88
+ # Auto Scaling Group(s).
85
89
  raise Capistrano::ASG::Rolling::StartInstanceRefreshError, e
86
90
  end
87
91
 
@@ -22,6 +22,8 @@ module Capistrano
22
22
  options = {}
23
23
  options[:region] = aws_region if aws_region
24
24
  options[:credentials] = aws_credentials if aws_credentials.set?
25
+ options[:retry_mode] = Configuration.aws_retry_mode
26
+ options[:retry_limit] = Configuration.aws_retry_limit
25
27
  options[:http_wire_trace] = true if ENV['AWS_HTTP_WIRE_TRACE'] == '1'
26
28
  options
27
29
  end
@@ -79,6 +79,22 @@ module Capistrano
79
79
  def instance_refresh_polling_interval
80
80
  fetch(:asg_instance_refresh_polling_interval, 30)
81
81
  end
82
+
83
+ def aws_retry_mode
84
+ fetch(:asg_aws_retry_mode, 'adaptive')
85
+ end
86
+
87
+ def aws_retry_limit
88
+ fetch(:asg_aws_retry_limit, 10)
89
+ end
90
+
91
+ def ami_wait_delay
92
+ fetch(:asg_ami_wait_delay, 15)
93
+ end
94
+
95
+ def ami_wait_max_attempts
96
+ fetch(:asg_ami_wait_max_attempts, 40)
97
+ end
82
98
  end
83
99
  end
84
100
  end
@@ -9,18 +9,34 @@ module Capistrano
9
9
  module Parallel
10
10
  module_function
11
11
 
12
+ # Runs the given block once per element of `work`, in parallel.
13
+ #
14
+ # All threads are joined before this method returns, so a failure in one
15
+ # block does not abandon the other in-flight threads. If any block
16
+ # raises, the first error is re-raised after all threads have completed;
17
+ # additional errors are surfaced via `Kernel.warn`.
12
18
  def run(work)
13
- result = Concurrent::Array.new
19
+ results = Concurrent::Array.new
20
+ errors = Concurrent::Array.new
14
21
 
15
22
  threads = work.map do |w|
16
23
  Thread.new do
17
- result << yield(w)
24
+ results << yield(w)
25
+ rescue StandardError => e
26
+ errors << e
18
27
  end
19
28
  end
20
29
 
21
30
  threads.each(&:join)
22
31
 
23
- result
32
+ if errors.any?
33
+ errors.drop(1).each do |e|
34
+ Kernel.warn("WARNING: parallel task failed: #{e.class}: #{e.message}")
35
+ end
36
+ raise errors.first
37
+ end
38
+
39
+ results
24
40
  end
25
41
  end
26
42
  end
@@ -3,7 +3,7 @@
3
3
  module Capistrano
4
4
  module ASG
5
5
  module Rolling
6
- VERSION = '0.7.0'
6
+ VERSION = '0.8.0'
7
7
  end
8
8
  end
9
9
  end
@@ -202,6 +202,12 @@ namespace :rolling do
202
202
  else
203
203
  logger.info "Auto Scaling Group: **#{name}**, status '#{refresh.status}'."
204
204
  end
205
+ rescue Aws::AutoScaling::Errors::ServiceError => e
206
+ # The instance refresh is still running in AWS even though we hit a
207
+ # transient API error (typically throttling that exceeded the SDK's
208
+ # retry budget). Log and retry on the next polling interval instead
209
+ # of aborting the deployment.
210
+ logger.warning "Auto Scaling Group: **#{name}**, failed to fetch status: #{e.class}: #{e.message} - retrying on next poll."
205
211
  end
206
212
  next if groups.empty?
207
213
 
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-asg-rolling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kentaa
8
+ - iRaiser
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2025-12-23 00:00:00.000000000 Z
12
+ date: 2026-05-22 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -52,6 +53,20 @@ dependencies:
52
53
  - - "~>"
53
54
  - !ruby/object:Gem::Version
54
55
  version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: simplecov
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.22'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.22'
55
70
  - !ruby/object:Gem::Dependency
56
71
  name: webmock
57
72
  requirement: !ruby/object:Gem::Requirement
@@ -130,7 +145,7 @@ dependencies:
130
145
  version: '1'
131
146
  description:
132
147
  email:
133
- - developers@kentaa.nl
148
+ - tech-arnhem@iraiser.eu
134
149
  executables: []
135
150
  extensions: []
136
151
  extra_rdoc_files: []