aws-sdk-core 3.90.1 → 3.91.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
  SHA1:
3
- metadata.gz: b55b3e3cd1c9ec04bc1d375d08ca93de5a8c0212
4
- data.tar.gz: 7e9f75a40eb67070b4fa0d5696193fb011196211
3
+ metadata.gz: '018176486b2589c3e5643f0517d600048b788239'
4
+ data.tar.gz: bf23afa4bc903911cc3a571b318eb38911a4cb62
5
5
  SHA512:
6
- metadata.gz: c3dde38d099f43ae112d5b7887c38bca099897df24295c871581a9d888f7f9d95adf908caf9976cba6b195211b7d1ee9e1d7defd1b908c9bcc2cec4e6b2a8a11
7
- data.tar.gz: 1c7d52fbbb564fd92a209d37c25e7f37a27206ec1461953b1f9aa0dee251379195af93494a9fb0a2d7e4d142ba4567fe69e334096b970fbacd9e36b2ca95e31d
6
+ metadata.gz: 8c5827b6dfca9a435419df7ec67f006179fe4656e909769e7545dbd4803b6723bdfedc7a9e89f23bff052d3e93428dcd39c9b803a1f35aba3ac26cfc3c33fb87
7
+ data.tar.gz: a244072123870020dbca0dee7bbe8f7057367b1ce81e18c7078b994e79a5f48c5ca5639e0df4113d4e68fdbc12627097751d21e45a65c4359e7d0abd4a548474
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.90.1
1
+ 3.91.0
@@ -28,7 +28,11 @@ module Aws
28
28
  [:assume_role_credentials, {}],
29
29
  [:shared_credentials, {}],
30
30
  [:process_credentials, {}],
31
- [:instance_profile_credentials, {}]
31
+ [:instance_profile_credentials, {
32
+ retries: @config ? @config.instance_profile_credentials_retries : 0,
33
+ http_open_timeout: @config ? @config.instance_profile_credentials_timeout : 1,
34
+ http_read_timeout: @config ? @config.instance_profile_credentials_timeout : 1
35
+ }]
32
36
  ]
33
37
  end
34
38
 
@@ -36,6 +36,16 @@ module Aws
36
36
  attr_accessor :code
37
37
 
38
38
  end
39
+
40
+ # @api private undocumented
41
+ def retryable?
42
+ false
43
+ end
44
+
45
+ # @api private undocumented
46
+ def throttling?
47
+ false
48
+ end
39
49
  end
40
50
 
41
51
  # Raised when InstanceProfileCredentialsProvider or
@@ -255,6 +265,15 @@ Known AWS regions include (not specific to this service):
255
265
 
256
266
  end
257
267
 
268
+ # Raised when attempting to retry a request
269
+ # and no capacity is available to retry (See adaptive retry_mode)
270
+ class RetryCapacityNotAvailableError < RuntimeError
271
+ def initialize(*args)
272
+ msg = 'Insufficient client side capacity available to retry request.'
273
+ super(msg)
274
+ end
275
+ end
276
+
258
277
  # This module is mixed into another module, providing dynamic
259
278
  # error classes. Error classes all inherit from {ServiceError}.
260
279
  #
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require_relative 'retries/error_inspector'
2
3
 
3
4
  module Aws
4
5
  module Plugins
@@ -141,7 +142,7 @@ all generated client side metrics. Defaults to an empty string.
141
142
  @handler.call(context)
142
143
  rescue StandardError => e
143
144
  # Handle SDK Exceptions
144
- inspector = Aws::Plugins::RetryErrors::ErrorInspector.new(
145
+ inspector = Retries::ErrorInspector.new(
145
146
  e,
146
147
  context.http_response.status_code
147
148
  )
@@ -0,0 +1,137 @@
1
+ module Aws
2
+ module Plugins
3
+ module Retries
4
+ # @api private
5
+ # Used only in 'adaptive' retry mode
6
+ class ClientRateLimiter
7
+ MIN_CAPACITY = 1
8
+ MIN_FILL_RATE = 0.5
9
+ SMOOTH = 0.8
10
+ # How much to scale back after a throttling response
11
+ BETA = 0.7
12
+ # Controls how aggressively we scale up after being throttled
13
+ SCALE_CONSTANT = 0.4
14
+
15
+ def initialize
16
+ @mutex = Mutex.new
17
+ @fill_rate = nil
18
+ @max_capacity = nil
19
+ @current_capacity = 0
20
+ @last_timestamp = nil
21
+ @enabled = false
22
+ @measured_tx_rate = 0
23
+ @last_tx_rate_bucket = Aws::Util.monotonic_seconds
24
+ @request_count = 0
25
+ @last_max_rate = 0
26
+ @last_throttle_time = Aws::Util.monotonic_seconds
27
+ @calculated_rate = nil
28
+ end
29
+
30
+ def token_bucket_acquire(amount, wait_to_fill = true)
31
+ # Client side throttling is not enabled until we see a
32
+ # throttling error
33
+ return unless @enabled
34
+
35
+ @mutex.synchronize do
36
+ token_bucket_refill
37
+
38
+ # Next see if we have enough capacity for the requested amount
39
+ while @current_capacity < amount
40
+ raise Aws::Errors::RetryCapacityNotAvailableError unless wait_to_fill
41
+ @mutex.sleep((amount - @current_capacity) / @fill_rate)
42
+ token_bucket_refill
43
+ end
44
+ @current_capacity -= amount
45
+ end
46
+ end
47
+
48
+ def update_sending_rate(is_throttling_error)
49
+ @mutex.synchronize do
50
+ update_measured_rate
51
+
52
+ if is_throttling_error
53
+ rate_to_use = if @enabled
54
+ [@measured_tx_rate, @fill_rate].min
55
+ else
56
+ @measured_tx_rate
57
+ end
58
+
59
+ # The fill_rate is from the token bucket
60
+ @last_max_rate = rate_to_use
61
+ calculate_time_window
62
+ @last_throttle_time = Aws::Util.monotonic_seconds
63
+ @calculated_rate = cubic_throttle(rate_to_use)
64
+ enable_token_bucket
65
+ else
66
+ calculate_time_window
67
+ @calculated_rate = cubic_success(Aws::Util.monotonic_seconds)
68
+ end
69
+
70
+ new_rate = [@calculated_rate, 2 * @measured_tx_rate].min
71
+ token_bucket_update_rate(new_rate)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def token_bucket_refill
78
+ timestamp = Aws::Util.monotonic_seconds
79
+ unless @last_timestamp
80
+ @last_timestamp = timestamp
81
+ return
82
+ end
83
+
84
+ fill_amount = (timestamp - @last_timestamp) * @fill_rate
85
+ @current_capacity = [
86
+ @max_capacity, @current_capacity + fill_amount
87
+ ].min
88
+
89
+ @last_timestamp = timestamp
90
+ end
91
+
92
+ def token_bucket_update_rate(new_rps)
93
+ # Refill based on our current rate before we update to the
94
+ # new fill rate
95
+ token_bucket_refill
96
+ @fill_rate = [new_rps, MIN_FILL_RATE].max
97
+ @max_capacity = [new_rps, MIN_CAPACITY].max
98
+ # When we scale down we can't have a current capacity that exceeds our
99
+ # max_capacity.
100
+ @current_capacity = [@current_capacity, @max_capacity].min
101
+ end
102
+
103
+ def enable_token_bucket
104
+ @enabled = true
105
+ end
106
+
107
+ def update_measured_rate
108
+ t = Aws::Util.monotonic_seconds
109
+ time_bucket = (t * 2).floor / 2.0
110
+ @request_count += 1
111
+ if time_bucket > @last_tx_rate_bucket
112
+ current_rate = @request_count / (time_bucket - @last_tx_rate_bucket)
113
+ @measured_tx_rate = (current_rate * SMOOTH) +
114
+ (@measured_tx_rate * (1 - SMOOTH))
115
+ @request_count = 0
116
+ @last_tx_rate_bucket = time_bucket
117
+ end
118
+ end
119
+
120
+ def calculate_time_window
121
+ # This is broken out into a separate calculation because it only
122
+ # gets updated when @last_max_rate changes so it can be cached.
123
+ @time_window = ((@last_max_rate * (1 - BETA)) / SCALE_CONSTANT)**(1.0 / 3)
124
+ end
125
+
126
+ def cubic_success(timestamp)
127
+ dt = timestamp - @last_throttle_time
128
+ (SCALE_CONSTANT * ((dt - @time_window)**3)) + @last_max_rate
129
+ end
130
+
131
+ def cubic_throttle(rate_to_use)
132
+ rate_to_use * BETA
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,63 @@
1
+ module Aws
2
+ module Plugins
3
+ module Retries
4
+
5
+ # @api private
6
+ class ClockSkew
7
+
8
+ CLOCK_SKEW_THRESHOLD = 5 * 60 # five minutes
9
+
10
+ def initialize
11
+ @mutex = Mutex.new
12
+ @endpoint_clock_corrections = Hash.new(0)
13
+ end
14
+
15
+ # Gets the clock_correction in seconds to apply to a given endpoint
16
+ # @param endpoint [URI / String]
17
+ def clock_correction(endpoint)
18
+ @mutex.synchronize { @endpoint_clock_corrections[endpoint.to_s] }
19
+ end
20
+
21
+ # Sets the clock correction for an endpoint
22
+ # @param endpoint [URI / String]
23
+ # @param correction [Number]
24
+ def set_clock_correction(endpoint, correction)
25
+ @mutex.synchronize { @endpoint_clock_corrections[endpoint.to_s] = correction }
26
+ end
27
+
28
+ # Determines whether a request has clock skew by comparing
29
+ # the current time against the server's time in the response
30
+ # @param context [Seahorse::Client::RequestContext]
31
+ def clock_skewed?(context)
32
+ server_time = server_time(context.http_response)
33
+ !!server_time && (Time.now.utc - server_time).abs > CLOCK_SKEW_THRESHOLD
34
+ end
35
+
36
+ # Update the stored clock skew value for an endpoint
37
+ # from the server's time in the response
38
+ # @param context [Seahorse::Client::RequestContext]
39
+ def update_clock_skew(context)
40
+ endpoint = context.http_request.endpoint
41
+ now_utc = Time.now.utc
42
+ server_time = server_time(context.http_response)
43
+ if server_time && (now_utc - server_time).abs > CLOCK_SKEW_THRESHOLD
44
+ set_clock_correction(endpoint, server_time - now_utc)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @param response [Seahorse::Client::Http::Response:]
51
+ def server_time(response)
52
+ begin
53
+ Time.parse(response.headers['date']).utc
54
+ rescue
55
+ nil
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,142 @@
1
+ module Aws
2
+ module Plugins
3
+ module Retries
4
+ # @api private
5
+ # This class will be obsolete when APIs contain modeled exceptions
6
+ class ErrorInspector
7
+ EXPIRED_CREDS = Set.new(
8
+ [
9
+ 'InvalidClientTokenId', # query services
10
+ 'UnrecognizedClientException', # json services
11
+ 'InvalidAccessKeyId', # s3
12
+ 'AuthFailure', # ec2
13
+ 'InvalidIdentityToken', # sts
14
+ 'ExpiredToken' # route53
15
+ ]
16
+ )
17
+
18
+ THROTTLING_ERRORS = Set.new(
19
+ [
20
+ 'Throttling', # query services
21
+ 'ThrottlingException', # json services
22
+ 'ThrottledException', # sns
23
+ 'RequestThrottled', # sqs
24
+ 'RequestThrottledException', # generic service
25
+ 'ProvisionedThroughputExceededException', # dynamodb
26
+ 'TransactionInProgressException', # dynamodb
27
+ 'RequestLimitExceeded', # ec2
28
+ 'BandwidthLimitExceeded', # cloud search
29
+ 'LimitExceededException', # kinesis
30
+ 'TooManyRequestsException', # batch
31
+ 'PriorRequestNotComplete', # route53
32
+ 'SlowDown', # s3
33
+ 'EC2ThrottledException' # ec2
34
+ ]
35
+ )
36
+
37
+ CHECKSUM_ERRORS = Set.new(
38
+ [
39
+ 'CRC32CheckFailed' # dynamodb
40
+ ]
41
+ )
42
+
43
+ NETWORKING_ERRORS = Set.new(
44
+ [
45
+ 'RequestTimeout', # s3
46
+ 'RequestTimeoutException', # glacier
47
+ 'IDPCommunicationError' # sts
48
+ ]
49
+ )
50
+
51
+ # See: https://github.com/aws/aws-sdk-net/blob/5810dfe401e0eac2e59d02276d4b479224b4538e/sdk/src/Core/Amazon.Runtime/Pipeline/RetryHandler/RetryPolicy.cs#L78
52
+ CLOCK_SKEW_ERRORS = Set.new(
53
+ [
54
+ 'RequestTimeTooSkewed',
55
+ 'RequestExpired',
56
+ 'InvalidSignatureException',
57
+ 'SignatureDoesNotMatch',
58
+ 'AuthFailure',
59
+ 'RequestInTheFuture'
60
+ ]
61
+ )
62
+
63
+ def initialize(error, http_status_code)
64
+ @error = error
65
+ @name = extract_name(@error)
66
+ @http_status_code = http_status_code
67
+ end
68
+
69
+ def expired_credentials?
70
+ !!(EXPIRED_CREDS.include?(@name) || @name.match(/expired/i))
71
+ end
72
+
73
+ def throttling_error?
74
+ !!(THROTTLING_ERRORS.include?(@name) ||
75
+ @name.match(/throttl/i) ||
76
+ @http_status_code == 429) ||
77
+ modeled_throttling?
78
+ end
79
+
80
+ def checksum?
81
+ CHECKSUM_ERRORS.include?(@name) || @error.is_a?(Errors::ChecksumError)
82
+ end
83
+
84
+ def networking?
85
+ @error.is_a?(Seahorse::Client::NetworkingError) ||
86
+ @error.is_a?(Errors::NoSuchEndpointError) ||
87
+ NETWORKING_ERRORS.include?(@name)
88
+ end
89
+
90
+ def server?
91
+ (500..599).cover?(@http_status_code)
92
+ end
93
+
94
+ def endpoint_discovery?(context)
95
+ return false unless context.operation.endpoint_discovery
96
+
97
+ @http_status_code == 421 ||
98
+ @name == 'InvalidEndpointException' ||
99
+ @error.is_a?(Errors::EndpointDiscoveryError)
100
+ end
101
+
102
+ def modeled_retryable?
103
+ @error.is_a?(Errors::ServiceError) && @error.retryable?
104
+ end
105
+
106
+ def modeled_throttling?
107
+ @error.is_a?(Errors::ServiceError) && @error.throttling?
108
+ end
109
+
110
+ def clock_skew?(context)
111
+ CLOCK_SKEW_ERRORS.include?(@name) &&
112
+ context.config.clock_skew.clock_skewed?(context)
113
+ end
114
+
115
+ def retryable?(context)
116
+ server? ||
117
+ modeled_retryable? ||
118
+ throttling_error? ||
119
+ networking? ||
120
+ checksum? ||
121
+ endpoint_discovery?(context) ||
122
+ (expired_credentials? && refreshable_credentials?(context)) ||
123
+ clock_skew?(context)
124
+ end
125
+
126
+ private
127
+
128
+ def refreshable_credentials?(context)
129
+ context.config.credentials.respond_to?(:refresh!)
130
+ end
131
+
132
+ def extract_name(error)
133
+ if error.is_a?(Errors::ServiceError)
134
+ error.class.code || error.class.name.to_s
135
+ else
136
+ error.class.name.to_s
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,57 @@
1
+ module Aws
2
+ module Plugins
3
+ module Retries
4
+
5
+ # @api private
6
+ # Used in 'standard' and 'adaptive' retry modes.
7
+ class RetryQuota
8
+ INITIAL_RETRY_TOKENS = 500
9
+ RETRY_COST = 5
10
+ NO_RETRY_INCREMENT = 1
11
+ TIMEOUT_RETRY_COST = 10
12
+
13
+ def initialize(opts = {})
14
+ @mutex = Mutex.new
15
+ @max_capacity = opts.fetch(:max_capacity, INITIAL_RETRY_TOKENS)
16
+ @available_capacity = @max_capacity
17
+ end
18
+
19
+ # check if there is sufficient capacity to retry
20
+ # and return it. If there is insufficient capacity
21
+ # return 0
22
+ # @return [Integer] The amount of capacity checked out
23
+ def checkout_capacity(error_inspector)
24
+ @mutex.synchronize do
25
+ capacity_amount = if error_inspector.networking?
26
+ TIMEOUT_RETRY_COST
27
+ else
28
+ RETRY_COST
29
+ end
30
+
31
+ # unable to acquire capacity
32
+ return 0 if capacity_amount > @available_capacity
33
+
34
+ @available_capacity -= capacity_amount
35
+ capacity_amount
36
+ end
37
+ end
38
+
39
+ # capacity_amount refers to the amount of capacity requested from
40
+ # the last retry. It can either be RETRY_COST, TIMEOUT_RETRY_COST,
41
+ # or unset.
42
+ def release(capacity_amount)
43
+ # Implementation note: The release() method is called for
44
+ # every API call. In the common case where the request is
45
+ # successful and we're at full capacity, we can avoid locking.
46
+ # We can't exceed max capacity so there's no work we have to do.
47
+ return if @available_capacity == @max_capacity
48
+
49
+ @mutex.synchronize do
50
+ @available_capacity += capacity_amount || NO_RETRY_INCREMENT
51
+ @available_capacity = [@available_capacity, @max_capacity].min
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end