aws-sdk-core 3.90.0 → 3.93.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 +4 -4
- data/VERSION +1 -1
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +1 -0
- data/lib/aws-sdk-core/binary/event_builder.rb +6 -6
- data/lib/aws-sdk-core/client_stubs.rb +9 -8
- data/lib/aws-sdk-core/credential_provider_chain.rb +18 -5
- data/lib/aws-sdk-core/errors.rb +19 -0
- data/lib/aws-sdk-core/json.rb +9 -10
- data/lib/aws-sdk-core/log/param_filter.rb +3 -3
- data/lib/aws-sdk-core/pageable_response.rb +34 -20
- data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +2 -1
- data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +137 -0
- data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +98 -0
- data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +142 -0
- data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +57 -0
- data/lib/aws-sdk-core/plugins/retry_errors.rb +289 -111
- data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -2
- data/lib/aws-sdk-core/plugins/stub_responses.rb +1 -0
- data/lib/aws-sdk-core/shared_config.rb +17 -11
- data/lib/aws-sdk-core/util.rb +4 -0
- data/lib/aws-sdk-sts.rb +7 -4
- data/lib/aws-sdk-sts/client.rb +68 -14
- data/lib/aws-sdk-sts/errors.rb +30 -8
- data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +4 -4
- data/lib/aws-sdk-sts/resource.rb +1 -0
- data/lib/seahorse/client/response.rb +3 -5
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6de3598b56d0c65e9932b033550214b8a5b44662
|
4
|
+
data.tar.gz: 40464e5ac916ef50c8cbabbee35098b263477f74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baa1c13fbe13e94c280cf68ab4db3756f98402aa256afd89bd22925288d0b296eb16fe8d0bd7b649db3919306ddedab230ca54c2c2671042854def6e0b729b95
|
7
|
+
data.tar.gz: ff2b486eab0f8f1de1b762396311eb6e399d14d32fdf9e3b34268cb1a6ff5369fb7a1d94fdf41ee6b5cea339929b8a0d4669de6e93e8cc15e088284cc927a6ac
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.93.0
|
@@ -5,7 +5,7 @@ module Aws
|
|
5
5
|
|
6
6
|
include Seahorse::Model::Shapes
|
7
7
|
|
8
|
-
# @param [Class]
|
8
|
+
# @param [Class] serializer_class
|
9
9
|
# @param [Seahorse::Model::ShapeRef] rules (of eventstream member)
|
10
10
|
def initialize(serializer_class, rules)
|
11
11
|
@serializer_class = serializer_class
|
@@ -59,7 +59,7 @@ module Aws
|
|
59
59
|
payload = _build_payload(streaming, m_ref, params[m_name])
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
|
64
64
|
event_ref.shape.members.each do |member_name, member_ref|
|
65
65
|
if member_ref.eventheader && params[member_name]
|
@@ -69,7 +69,7 @@ module Aws
|
|
69
69
|
value: header_value
|
70
70
|
)
|
71
71
|
elsif member_ref.eventpayload && params[member_name]
|
72
|
-
# explicit payload
|
72
|
+
# explicit payload
|
73
73
|
streaming, content_type = _content_type(member_ref.shape)
|
74
74
|
|
75
75
|
es_headers[":content-type"] = Aws::EventStream::HeaderValue.new(
|
@@ -99,7 +99,7 @@ module Aws
|
|
99
99
|
"Unsupport eventpayload shape: #{shape.name}")
|
100
100
|
end
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
def _header_value_type(shape, value)
|
104
104
|
case shape
|
105
105
|
when StringShape then "string"
|
@@ -107,9 +107,9 @@ module Aws
|
|
107
107
|
when TimestampShape then "timestamp"
|
108
108
|
when BlobShape then "bytes"
|
109
109
|
when BooleanShape then !!value ? "bool_true" : "bool_false"
|
110
|
-
else
|
110
|
+
else
|
111
111
|
raise Aws::Errors::EventStreamBuilderError.new(
|
112
|
-
"Unsupported eventheader shape: #{shape.name}")
|
112
|
+
"Unsupported eventheader shape: #{shape.name}")
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -171,7 +171,6 @@ module Aws
|
|
171
171
|
# @raise [RuntimeError] Raises a runtime error when called
|
172
172
|
# on a client that has not enabled response stubbing via
|
173
173
|
# `:stub_responses => true`.
|
174
|
-
#
|
175
174
|
def stub_responses(operation_name, *stubs)
|
176
175
|
if config.stub_responses
|
177
176
|
apply_stubs(operation_name, stubs.flatten)
|
@@ -182,13 +181,15 @@ module Aws
|
|
182
181
|
end
|
183
182
|
end
|
184
183
|
|
185
|
-
# Allows you to access all of the requests that the stubbed client has made
|
186
|
-
#
|
187
|
-
# @
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
184
|
+
# Allows you to access all of the requests that the stubbed client has made.
|
185
|
+
#
|
186
|
+
# @param [Hash] options The options for the api requests.
|
187
|
+
# @option options [Boolean] :exclude_presign (false) Set to true to filter
|
188
|
+
# out unsent requests from generated presigned urls.
|
189
|
+
# @return [Array] Returns an array of the api requests made. Each request
|
190
|
+
# object contains the :operation_name, :params, and :context.
|
191
|
+
# @raise [NotImplementedError] Raises `NotImplementedError` when the client
|
192
|
+
# is not stubbed.
|
192
193
|
def api_requests(options = {})
|
193
194
|
if config.stub_responses
|
194
195
|
if options[:exclude_presign]
|
@@ -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
|
|
@@ -44,7 +48,10 @@ module Aws
|
|
44
48
|
|
45
49
|
def static_profile_assume_role_web_identity_credentials(options)
|
46
50
|
if Aws.shared_config.config_enabled? && options[:config] && options[:config].profile
|
47
|
-
Aws.shared_config.assume_role_web_identity_credentials_from_config(
|
51
|
+
Aws.shared_config.assume_role_web_identity_credentials_from_config(
|
52
|
+
profile: options[:config].profile,
|
53
|
+
region: options[:config].region
|
54
|
+
)
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
@@ -113,15 +120,21 @@ module Aws
|
|
113
120
|
end
|
114
121
|
|
115
122
|
def assume_role_web_identity_credentials(options)
|
123
|
+
region = options[:config].region if options[:config]
|
116
124
|
if (role_arn = ENV['AWS_ROLE_ARN']) && (token_file = ENV['AWS_WEB_IDENTITY_TOKEN_FILE'])
|
117
|
-
|
125
|
+
cfg = {
|
118
126
|
role_arn: role_arn,
|
119
127
|
web_identity_token_file: token_file,
|
120
128
|
role_session_name: ENV['AWS_ROLE_SESSION_NAME']
|
121
|
-
|
129
|
+
}
|
130
|
+
cfg[:region] = region if region
|
131
|
+
AssumeRoleWebIdentityCredentials.new(cfg)
|
122
132
|
elsif Aws.shared_config.config_enabled?
|
123
133
|
profile = options[:config].profile if options[:config]
|
124
|
-
Aws.shared_config.assume_role_web_identity_credentials_from_config(
|
134
|
+
Aws.shared_config.assume_role_web_identity_credentials_from_config(
|
135
|
+
profile: profile,
|
136
|
+
region: region
|
137
|
+
)
|
125
138
|
end
|
126
139
|
end
|
127
140
|
|
data/lib/aws-sdk-core/errors.rb
CHANGED
@@ -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
|
#
|
data/lib/aws-sdk-core/json.rb
CHANGED
@@ -7,28 +7,24 @@ require_relative 'json/parser'
|
|
7
7
|
module Aws
|
8
8
|
# @api private
|
9
9
|
module Json
|
10
|
-
|
11
10
|
class ParseError < StandardError
|
12
|
-
|
13
11
|
def initialize(error)
|
14
12
|
@error = error
|
15
13
|
super(error.message)
|
16
14
|
end
|
17
15
|
|
18
16
|
attr_reader :error
|
19
|
-
|
20
17
|
end
|
21
18
|
|
22
19
|
class << self
|
23
|
-
|
24
20
|
def load(json)
|
25
21
|
ENGINE.load(json, *ENGINE_LOAD_OPTIONS)
|
26
22
|
rescue *ENGINE_ERRORS => e
|
27
|
-
raise ParseError
|
23
|
+
raise ParseError, e
|
28
24
|
end
|
29
25
|
|
30
26
|
def load_file(path)
|
31
|
-
|
27
|
+
load(File.open(path, 'r', encoding: 'UTF-8', &:read))
|
32
28
|
end
|
33
29
|
|
34
30
|
def dump(value)
|
@@ -39,7 +35,12 @@ module Aws
|
|
39
35
|
|
40
36
|
def oj_engine
|
41
37
|
require 'oj'
|
42
|
-
[
|
38
|
+
[
|
39
|
+
Oj,
|
40
|
+
[{ mode: :compat, symbol_keys: false }],
|
41
|
+
[{ mode: :compat }],
|
42
|
+
oj_parse_error
|
43
|
+
]
|
43
44
|
rescue LoadError
|
44
45
|
false
|
45
46
|
end
|
@@ -50,17 +51,15 @@ module Aws
|
|
50
51
|
|
51
52
|
def oj_parse_error
|
52
53
|
if Oj.const_defined?('ParseError')
|
53
|
-
[Oj::ParseError, EncodingError]
|
54
|
+
[Oj::ParseError, EncodingError, JSON::ParserError]
|
54
55
|
else
|
55
56
|
[SyntaxError]
|
56
57
|
end
|
57
58
|
end
|
58
|
-
|
59
59
|
end
|
60
60
|
|
61
61
|
# @api private
|
62
62
|
ENGINE, ENGINE_LOAD_OPTIONS, ENGINE_DUMP_OPTIONS, ENGINE_ERRORS =
|
63
63
|
oj_engine || json_engine
|
64
|
-
|
65
64
|
end
|
66
65
|
end
|
@@ -7,11 +7,11 @@ module Aws
|
|
7
7
|
|
8
8
|
# A managed list of sensitive parameters that should be filtered from
|
9
9
|
# logs. This is updated automatically as part of each release. See the
|
10
|
-
# `tasks/sensitive.rake` for more information.
|
10
|
+
# `tasks/update-sensitive-params.rake` for more information.
|
11
11
|
#
|
12
12
|
# @api private
|
13
13
|
# begin
|
14
|
-
SENSITIVE = [:access_token, :account_name, :account_password, :address, :admin_contact, :admin_password, :alexa_for_business_room_arn, :artifact_credentials, :auth_code, :authentication_token, :authorization_result, :backup_plan_tags, :backup_vault_tags, :base_32_string_seed, :block, :block_address, :block_data, :blocks, :body, :bot_configuration, :bot_email, :calling_name, :cause, :client_id, :client_request_token, :client_secret, :comment, :configuration, :copy_source_sse_customer_key, :credentials, :current_password, :custom_attributes, :custom_private_key, :db_password, :default_phone_number, :definition, :description, :destination_access_token, :digest_tip_address, :display_name, :domain_signing_private_key, :e164_phone_number, :email, :email_address, :email_message, :embed_url, :error, :external_model_endpoint_data_blobs, :external_user_id, :feedback_token, :file, :first_name, :full_name, :host_key, :id, :id_token, :input, :input_text, :ion_text, :join_token, :key_id, :key_material, :key_store_password, :kms_key_id, :kms_master_key_id, :lambda_function_arn, :last_name, :local_console_password, :master_account_email, :master_user_name, :master_user_password, :meeting_host_id, :message, :metadata, :name, :new_password, :next_password, :notes, :number, :old_password, :outbound_events_https_endpoint, :output, :owner_information, :parameters, :passphrase, :password, :payload, :phone_number, :plaintext, :previous_password, :primary_email, :primary_provisioned_number, :private_key, :private_key_plaintext, :proof, :proposed_password, :public_key, :qr_code_png, :query, :random_password, :recovery_point_tags, :refresh_token, :registrant_contact, :request_attributes, :restore_metadata, :revision, :search_query, :secret_access_key, :secret_binary, :secret_code, :secret_hash, :secret_string, :secret_to_authenticate_initiator, :secret_to_authenticate_target, :security_token, :service_password, :session_attributes, :session_token, :share_notes, :shared_secret, :slots, :sns_topic_arn, :source_access_token, :sqs_queue_arn, :sse_customer_key, :ssekms_encryption_context, :ssekms_key_id, :status_message, :tag_key_list, :tags, :target_address, :task_parameters, :tech_contact, :temporary_password, :text, :token, :trust_password, :type, :upload_credentials, :upload_url, :uri, :user_data, :user_email, :user_name, :user_password, :username, :value, :values, :variables, :vpn_psk, :zip_file]
|
14
|
+
SENSITIVE = [:access_token, :account_name, :account_password, :address, :admin_contact, :admin_password, :alexa_for_business_room_arn, :artifact_credentials, :auth_code, :authentication_token, :authorization_result, :backup_plan_tags, :backup_vault_tags, :base_32_string_seed, :block, :block_address, :block_data, :blocks, :body, :bot_configuration, :bot_email, :calling_name, :cause, :client_id, :client_request_token, :client_secret, :comment, :configuration, :copy_source_sse_customer_key, :credentials, :current_password, :custom_attributes, :custom_private_key, :db_password, :default_phone_number, :definition, :description, :destination_access_token, :digest_tip_address, :display_name, :domain_signing_private_key, :e164_phone_number, :email, :email_address, :email_message, :embed_url, :error, :external_model_endpoint_data_blobs, :external_user_id, :fall_back_phone_number, :feedback_token, :file, :first_name, :full_name, :host_key, :id, :id_token, :input, :input_text, :ion_text, :join_token, :key_id, :key_material, :key_store_password, :kms_key_id, :kms_master_key_id, :lambda_function_arn, :last_name, :local_console_password, :master_account_email, :master_user_name, :master_user_password, :meeting_host_id, :message, :metadata, :name, :new_password, :next_password, :notes, :number, :old_password, :outbound_events_https_endpoint, :output, :owner_information, :parameters, :passphrase, :password, :payload, :phone_number, :plaintext, :previous_password, :primary_email, :primary_provisioned_number, :private_key, :private_key_plaintext, :proof, :proposed_password, :proxy_phone_number, :public_key, :qr_code_png, :query, :random_password, :recovery_point_tags, :refresh_token, :registrant_contact, :request_attributes, :restore_metadata, :revision, :search_query, :secret_access_key, :secret_binary, :secret_code, :secret_hash, :secret_string, :secret_to_authenticate_initiator, :secret_to_authenticate_target, :security_token, :service_password, :session_attributes, :session_token, :share_notes, :shared_secret, :slots, :sns_topic_arn, :source_access_token, :sqs_queue_arn, :sse_customer_key, :ssekms_encryption_context, :ssekms_key_id, :status_message, :tag_key_list, :tags, :target_address, :task_parameters, :tech_contact, :temporary_password, :text, :token, :trust_password, :type, :upload_credentials, :upload_url, :uri, :user_data, :user_email, :user_name, :user_password, :username, :value, :values, :variables, :vpn_psk, :zip_file]
|
15
15
|
# end
|
16
16
|
|
17
17
|
def initialize(options = {})
|
@@ -31,7 +31,7 @@ module Aws
|
|
31
31
|
def filter_hash(values)
|
32
32
|
filtered = {}
|
33
33
|
values.each_pair do |key, value|
|
34
|
-
filtered[key] = @filters.
|
34
|
+
filtered[key] = @filters.any? { |f| f.to_s.casecmp(key.to_s).zero? } ? '[FILTERED]' : filter(value)
|
35
35
|
end
|
36
36
|
filtered
|
37
37
|
end
|
@@ -1,32 +1,46 @@
|
|
1
1
|
module Aws
|
2
2
|
|
3
|
-
# Decorates a {Seahorse::Client::Response} with paging methods
|
3
|
+
# Decorates a {Seahorse::Client::Response} with paging convenience methods.
|
4
|
+
# Some AWS calls provide paged responses to limit the amount of data returned
|
5
|
+
# with each response. To optimize for latency, some APIs may return an
|
6
|
+
# inconsistent number of responses per page. You should rely on the values of
|
7
|
+
# the `next_page?` method or using enumerable methods such as `each`
|
8
|
+
# rather than the number of items returned to iterate through results.
|
9
|
+
# See below for examples.
|
4
10
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
11
|
+
# # Paged Responses Are Enumerable
|
12
|
+
# The simplest way to handle paged response data is to use the built-in
|
13
|
+
# enumerator in the response object, as shown in the following example.
|
8
14
|
#
|
9
|
-
#
|
10
|
-
# resp = resp.next_page
|
11
|
-
# resp.last_page?
|
12
|
-
# #=> true
|
15
|
+
# s3 = Aws::S3::Client.new
|
13
16
|
#
|
14
|
-
#
|
15
|
-
#
|
17
|
+
# s3.list_objects(bucket:'aws-sdk').each do |response|
|
18
|
+
# puts response.contents.map(&:key)
|
19
|
+
# end
|
16
20
|
#
|
17
|
-
#
|
21
|
+
# This yields one response object per API call made, and enumerates objects
|
22
|
+
# in the named bucket. The SDK retrieves additional pages of data to
|
23
|
+
# complete the request.
|
18
24
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
+
# # Handling Paged Responses Manually
|
26
|
+
# To handle paging yourself, use the response’s `next_page?` method to verify
|
27
|
+
# there are more pages to retrieve, or use the last_page? method to verify
|
28
|
+
# there are no more pages to retrieve.
|
29
|
+
#
|
30
|
+
# If there are more pages, use the `next_page` method to retrieve the
|
31
|
+
# next page of results, as shown in the following example.
|
25
32
|
#
|
26
|
-
#
|
33
|
+
# s3 = Aws::S3::Client.new
|
27
34
|
#
|
28
|
-
#
|
29
|
-
#
|
35
|
+
# # Get the first page of data
|
36
|
+
# response = s3.list_objects(bucket:'aws-sdk')
|
37
|
+
#
|
38
|
+
# # Get additional pages
|
39
|
+
# while response.next_page? do
|
40
|
+
# response = response.next_page
|
41
|
+
# # Use the response data here...
|
42
|
+
# puts response.contents.map(&:key)
|
43
|
+
# end
|
30
44
|
#
|
31
45
|
module PageableResponse
|
32
46
|
|
@@ -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 =
|
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
|