aws-sdk-core 3.90.1 → 3.91.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
  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