hearth 1.0.0.pre2 → 1.0.0.pre3
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/CHANGELOG.md +5 -0
- data/VERSION +1 -1
- data/lib/hearth/anonymous_auth_resolver.rb +11 -0
- data/lib/hearth/auth_schemes/anonymous.rb +3 -3
- data/lib/hearth/auth_schemes.rb +3 -3
- data/lib/hearth/client.rb +66 -0
- data/lib/hearth/client_stubs.rb +1 -3
- data/lib/hearth/config/resolver.rb +6 -5
- data/lib/hearth/context.rb +1 -0
- data/lib/hearth/dns/host_address.rb +20 -16
- data/lib/hearth/endpoint_rules.rb +154 -0
- data/lib/hearth/http/client.rb +5 -7
- data/lib/hearth/http/error_inspector.rb +2 -2
- data/lib/hearth/http/field.rb +4 -19
- data/lib/hearth/http/header_list_builder.rb +42 -0
- data/lib/hearth/http/header_list_parser.rb +92 -0
- data/lib/hearth/http/middleware/content_length.rb +3 -3
- data/lib/hearth/http/middleware/content_md5.rb +0 -1
- data/lib/hearth/http/middleware/request_compression.rb +7 -10
- data/lib/hearth/http.rb +2 -0
- data/lib/hearth/{identity_resolver.rb → identity_provider.rb} +1 -1
- data/lib/hearth/interceptor_context.rb +8 -4
- data/lib/hearth/interceptors.rb +2 -1
- data/lib/hearth/json.rb +4 -4
- data/lib/hearth/middleware/auth.rb +9 -6
- data/lib/hearth/middleware/build.rb +0 -1
- data/lib/hearth/middleware/endpoint.rb +79 -0
- data/lib/hearth/middleware/host_prefix.rb +1 -2
- data/lib/hearth/middleware/initialize.rb +0 -1
- data/lib/hearth/middleware/parse.rb +0 -1
- data/lib/hearth/middleware/retry.rb +9 -2
- data/lib/hearth/middleware/send.rb +0 -1
- data/lib/hearth/middleware.rb +1 -0
- data/lib/hearth/middleware_stack.rb +1 -1
- data/lib/hearth/number_helper.rb +1 -1
- data/lib/hearth/query/param.rb +7 -3
- data/lib/hearth/query/param_matcher.rb +5 -6
- data/lib/hearth/{refreshing_identity_resolver.rb → refreshing_identity_provider.rb} +2 -2
- data/lib/hearth/request.rb +2 -2
- data/lib/hearth/response.rb +5 -2
- data/lib/hearth/retry/adaptive.rb +2 -2
- data/lib/hearth/retry/client_rate_limiter.rb +8 -6
- data/lib/hearth/retry/exponential_backoff.rb +1 -1
- data/lib/hearth/retry/standard.rb +2 -2
- data/lib/hearth/retry.rb +16 -3
- data/lib/hearth/structure.rb +7 -3
- data/lib/hearth/stubs.rb +12 -4
- data/lib/hearth/time_helper.rb +1 -2
- data/lib/hearth/validator.rb +37 -21
- data/lib/hearth/waiters/poller.rb +4 -2
- data/lib/hearth/waiters/waiter.rb +6 -5
- data/lib/hearth/xml/node.rb +0 -1
- data/lib/hearth/xml/node_matcher.rb +0 -1
- data/lib/hearth.rb +8 -4
- data/sig/lib/hearth/aliases.rbs +5 -3
- data/sig/lib/hearth/anonymous_auth_resolver.rbs +5 -0
- data/sig/lib/hearth/auth_schemes.rbs +1 -1
- data/sig/lib/hearth/client.rbs +9 -0
- data/sig/lib/hearth/configuration.rbs +2 -2
- data/sig/lib/hearth/dns/host_address.rbs +1 -3
- data/sig/lib/hearth/dns/host_resolver.rbs +3 -3
- data/sig/lib/hearth/endpoint_rules.rbs +17 -0
- data/sig/lib/hearth/http/field.rbs +1 -1
- data/sig/lib/hearth/http/fields.rbs +1 -1
- data/sig/lib/hearth/http/header_list_builder.rbs +15 -0
- data/sig/lib/hearth/http/header_list_parser.rbs +19 -0
- data/sig/lib/hearth/http/networking_error.rbs +6 -0
- data/sig/lib/hearth/http/response.rbs +1 -1
- data/sig/lib/hearth/identities.rbs +1 -1
- data/sig/lib/hearth/{identity_resolver.rbs → identity_provider.rbs} +1 -1
- data/sig/lib/hearth/interceptor_context.rbs +4 -2
- data/sig/lib/hearth/interfaces.rbs +52 -30
- data/sig/lib/hearth/json/parse_error.rbs +9 -0
- data/sig/lib/hearth/networking_error.rbs +7 -0
- data/sig/lib/hearth/output.rbs +4 -4
- data/sig/lib/hearth/plugin_list.rbs +5 -7
- data/sig/lib/hearth/query/param.rbs +2 -2
- data/sig/lib/hearth/refreshing_identity_provider.rbs +10 -0
- data/sig/lib/hearth/request.rbs +2 -2
- data/sig/lib/hearth/response.rbs +2 -2
- data/sig/lib/hearth/retry/exponential_backoff.rbs +1 -1
- data/sig/lib/hearth/retry.rbs +1 -1
- data/sig/lib/hearth/structure.rbs +1 -2
- data/sig/lib/hearth/stubs.rbs +9 -0
- data/sig/lib/hearth/union.rbs +1 -1
- data/sig/lib/hearth/xml/parse_error.rbs +9 -0
- metadata +26 -10
- data/lib/hearth/retry/strategy.rb +0 -20
@@ -5,7 +5,6 @@ module Hearth
|
|
5
5
|
module Middleware
|
6
6
|
# A middleware that compresses the request body and
|
7
7
|
# adds the Content-Encoding header
|
8
|
-
# @api private
|
9
8
|
class RequestCompression
|
10
9
|
include Hearth::Middleware::Logging
|
11
10
|
|
@@ -62,17 +61,16 @@ module Hearth
|
|
62
61
|
def update_content_encoding(encoding, request)
|
63
62
|
headers = request.headers
|
64
63
|
if headers['Content-Encoding']
|
65
|
-
headers['Content-Encoding'] += "
|
64
|
+
headers['Content-Encoding'] += ", #{encoding}"
|
66
65
|
else
|
67
66
|
headers['Content-Encoding'] = encoding
|
68
67
|
end
|
69
68
|
end
|
70
69
|
|
71
70
|
def compress_body(encoding, request)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
71
|
+
return unless encoding == 'gzip'
|
72
|
+
|
73
|
+
gzip_compress(request)
|
76
74
|
update_content_encoding(encoding, request)
|
77
75
|
end
|
78
76
|
|
@@ -100,10 +98,9 @@ module Hearth
|
|
100
98
|
end
|
101
99
|
|
102
100
|
def compress_streaming_body(encoding, request)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
101
|
+
return unless encoding == 'gzip'
|
102
|
+
|
103
|
+
request.body = GzipIO.new(request.body)
|
107
104
|
update_content_encoding(encoding, request)
|
108
105
|
end
|
109
106
|
|
data/lib/hearth/http.rb
CHANGED
@@ -7,6 +7,8 @@ require_relative 'http/error_inspector'
|
|
7
7
|
require_relative 'http/error_parser'
|
8
8
|
require_relative 'http/field'
|
9
9
|
require_relative 'http/fields'
|
10
|
+
require_relative 'http/header_list_builder'
|
11
|
+
require_relative 'http/header_list_parser'
|
10
12
|
require_relative 'http/middleware'
|
11
13
|
require_relative 'http/networking_error'
|
12
14
|
require_relative 'http/request'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Hearth
|
4
4
|
# Basic Identity resolver that uses a proc to resolve an Identity.
|
5
|
-
class
|
5
|
+
class IdentityProvider
|
6
6
|
# @param [Proc] proc A proc that takes identity properties (Hash)
|
7
7
|
# and returns a {Hearth::Identities::Base}.
|
8
8
|
def initialize(proc)
|
@@ -5,17 +5,18 @@ module Hearth
|
|
5
5
|
# context to read and modify the input, request, response, and output.
|
6
6
|
# Attributes can be used to pass additional data between interceptors.
|
7
7
|
class InterceptorContext
|
8
|
-
# @param [
|
8
|
+
# @param [Hearth::Structure] input
|
9
9
|
# @param [Hearth::Request] request
|
10
10
|
# @param [Hearth::Response] response
|
11
11
|
# @param [Hearth::Output] output
|
12
|
-
# @param [
|
13
|
-
def initialize(input:, request:, response:, output:,
|
12
|
+
# @param [Logger] logger
|
13
|
+
def initialize(input:, request:, response:, output:, logger:)
|
14
14
|
@input = input
|
15
15
|
@request = request
|
16
16
|
@response = response
|
17
17
|
@output = output
|
18
|
-
@
|
18
|
+
@logger = logger
|
19
|
+
@attributes = {}
|
19
20
|
end
|
20
21
|
|
21
22
|
# @return [Struct] Modeled input, i.e. Types::<Operation>Input
|
@@ -30,6 +31,9 @@ module Hearth
|
|
30
31
|
# @return [Hearth::Output] Operation output
|
31
32
|
attr_reader :output
|
32
33
|
|
34
|
+
# @return [Logger] logger
|
35
|
+
attr_reader :logger
|
36
|
+
|
33
37
|
# @return [Hash] attributes Additional interceptor data
|
34
38
|
attr_reader :attributes
|
35
39
|
end
|
data/lib/hearth/interceptors.rb
CHANGED
data/lib/hearth/json.rb
CHANGED
@@ -12,10 +12,10 @@ module Hearth
|
|
12
12
|
class << self
|
13
13
|
# @param [String] json
|
14
14
|
# @return [Hash]
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def parse(json)
|
16
|
+
return nil if json.empty?
|
17
|
+
|
18
|
+
::JSON.parse(json)
|
19
19
|
rescue ::JSON::ParserError => e
|
20
20
|
raise ParseError, e
|
21
21
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Hearth
|
4
4
|
module Middleware
|
5
5
|
# A middleware that resolves identities for signing requests.
|
6
|
-
# @api private
|
7
6
|
class Auth
|
8
7
|
include Middleware::Logging
|
9
8
|
|
@@ -23,11 +22,11 @@ module Hearth
|
|
23
22
|
@auth_params = auth_params
|
24
23
|
@auth_schemes = auth_schemes.to_h { |s| [s.scheme_id, s] }
|
25
24
|
|
26
|
-
@
|
25
|
+
@identity_providers = {}
|
27
26
|
kwargs.each do |key, value|
|
28
27
|
next unless key.superclass == Hearth::Identities::Base
|
29
28
|
|
30
|
-
@
|
29
|
+
@identity_providers[key] = value
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
@@ -46,6 +45,7 @@ module Hearth
|
|
46
45
|
private
|
47
46
|
|
48
47
|
ResolvedAuth = Struct.new(
|
48
|
+
:scheme_id,
|
49
49
|
:signer,
|
50
50
|
:signer_properties,
|
51
51
|
:identity,
|
@@ -56,6 +56,8 @@ module Hearth
|
|
56
56
|
def resolve_auth(auth_options)
|
57
57
|
failures = []
|
58
58
|
|
59
|
+
raise 'No auth options were resolved' if auth_options.empty?
|
60
|
+
|
59
61
|
auth_options.each do |auth_option|
|
60
62
|
auth_scheme = @auth_schemes[auth_option.scheme_id]
|
61
63
|
resolved_auth = try_load_auth_scheme(
|
@@ -78,17 +80,18 @@ module Hearth
|
|
78
80
|
return
|
79
81
|
end
|
80
82
|
|
81
|
-
|
82
|
-
unless
|
83
|
+
identity_provider = auth_scheme.identity_provider(@identity_providers)
|
84
|
+
unless identity_provider
|
83
85
|
failures << "Auth scheme #{scheme_id} did not have an " \
|
84
86
|
'identity resolver configured'
|
85
87
|
return
|
86
88
|
end
|
87
89
|
|
88
90
|
identity_properties = auth_option.identity_properties
|
89
|
-
identity =
|
91
|
+
identity = identity_provider.identity(identity_properties)
|
90
92
|
|
91
93
|
ResolvedAuth.new(
|
94
|
+
scheme_id: scheme_id,
|
92
95
|
identity: identity,
|
93
96
|
identity_properties: auth_option.identity_properties,
|
94
97
|
signer: auth_scheme.signer,
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# in Hearth middleware
|
4
|
+
module Hearth
|
5
|
+
module Middleware
|
6
|
+
# Resolves endpoints from endpoint parameters and modifies
|
7
|
+
# the request with resolved endpoint, headers and auth schemes.
|
8
|
+
class Endpoint
|
9
|
+
include Middleware::Logging
|
10
|
+
|
11
|
+
# @param [Class] app The next middleware in the stack.
|
12
|
+
# @param [#resolve(endpoint_params)] endpoint_resolver An object
|
13
|
+
# that responds to a `resolve(endpoint_params)` method
|
14
|
+
# where `endpoint_params` is a service specific struct.
|
15
|
+
# The method must return an {Hearth::Endpoints::Endpoint} object.
|
16
|
+
# @param [#build(config, input, context)] param_builder An object that
|
17
|
+
# responds to a `build(config, input, context)` method and returns
|
18
|
+
# an endpoint_params object.
|
19
|
+
def initialize(
|
20
|
+
app, endpoint_resolver:, param_builder:, **kwargs
|
21
|
+
)
|
22
|
+
@app = app
|
23
|
+
@param_builder = param_builder
|
24
|
+
@endpoint_resolver = endpoint_resolver
|
25
|
+
@config = kwargs
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(input, context)
|
29
|
+
params = @param_builder.build(@config, input, context)
|
30
|
+
log_debug(context, "Endpoint params: #{params}")
|
31
|
+
endpoint = @endpoint_resolver.resolve(params)
|
32
|
+
log_debug(context, "Resolved endpoint: #{endpoint}")
|
33
|
+
update_request(context, endpoint)
|
34
|
+
log_debug(context, "Updated request: #{context.request}")
|
35
|
+
update_auth_properties(context, endpoint.auth_schemes)
|
36
|
+
log_debug(context, "Updated auth properties: #{context.auth}")
|
37
|
+
|
38
|
+
@app.call(input, context)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# apply the resolved endpoint to the request
|
44
|
+
def update_request(context, endpoint)
|
45
|
+
context.request.uri = merge_endpoints(
|
46
|
+
URI(endpoint.uri), context.request.uri
|
47
|
+
)
|
48
|
+
endpoint.headers.each do |key, val|
|
49
|
+
context.request.headers[key] = val
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# merge the path and query parameters from serialization
|
54
|
+
# URIs from endpoint resolution MUST contain port and hostname
|
55
|
+
# and MAY contain port and base path.
|
56
|
+
def merge_endpoints(resolved_uri, request_uri)
|
57
|
+
merged = URI(resolved_uri)
|
58
|
+
merged.path = resolved_uri.path + request_uri.path
|
59
|
+
merged.query = request_uri.query
|
60
|
+
merged
|
61
|
+
end
|
62
|
+
|
63
|
+
# merge properties from the endpoint resolved auth schemes onto
|
64
|
+
# the auth scheme resolved by the auth resolver.
|
65
|
+
def update_auth_properties(context, auth_schemes)
|
66
|
+
context[:endpoint_auth_schemes] = auth_schemes
|
67
|
+
return unless context.auth
|
68
|
+
|
69
|
+
matching = auth_schemes.find do |a|
|
70
|
+
context.auth.scheme_id == a.scheme_id
|
71
|
+
end
|
72
|
+
|
73
|
+
return unless matching
|
74
|
+
|
75
|
+
context.auth.signer_properties.merge!(matching.properties)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Hearth
|
4
4
|
module Middleware
|
5
5
|
# A middleware that prefixes the host.
|
6
|
-
# @api private
|
7
6
|
class HostPrefix
|
8
7
|
include Middleware::Logging
|
9
8
|
|
@@ -37,7 +36,7 @@ module Hearth
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def apply_labels(host_prefix, input)
|
40
|
-
host_prefix.gsub(/\{
|
39
|
+
host_prefix.gsub(/\{.+?}/) do |host_label|
|
41
40
|
key = host_label.delete('{}')
|
42
41
|
value = input[key.to_sym]
|
43
42
|
if value.nil? || value.empty?
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Hearth
|
4
4
|
module Middleware
|
5
5
|
# A middleware that retries the request using a retry strategy.
|
6
|
-
# @api private
|
7
6
|
class Retry
|
8
7
|
include Middleware::Logging
|
9
8
|
|
@@ -75,6 +74,8 @@ module Hearth
|
|
75
74
|
|
76
75
|
if (error = output.error)
|
77
76
|
log_debug(context, "Request failed with error: #{error}")
|
77
|
+
break unless retryable?(context.request)
|
78
|
+
|
78
79
|
error_info = @error_inspector_class.new(error, context.response)
|
79
80
|
token = @retry_strategy.refresh_retry_token(token, error_info)
|
80
81
|
break unless token
|
@@ -93,14 +94,20 @@ module Hearth
|
|
93
94
|
@retries += 1
|
94
95
|
end
|
95
96
|
log_debug(context, 'Finished retry loop')
|
97
|
+
log_debug(context, "Total retries: #{@retries}")
|
96
98
|
output
|
97
99
|
end
|
98
100
|
|
99
101
|
private
|
100
102
|
|
103
|
+
def retryable?(request)
|
104
|
+
# IO responds to #rewind however it returns an illegal seek error
|
105
|
+
request.body.respond_to?(:rewind) && !request.body.instance_of?(IO)
|
106
|
+
end
|
107
|
+
|
101
108
|
def reset_request(context)
|
102
109
|
request = context.request
|
103
|
-
request.body.rewind
|
110
|
+
request.body.rewind
|
104
111
|
|
105
112
|
context.auth.signer.reset(
|
106
113
|
request: request,
|
data/lib/hearth/middleware.rb
CHANGED
data/lib/hearth/number_helper.rb
CHANGED
data/lib/hearth/query/param.rb
CHANGED
@@ -5,7 +5,7 @@ module Hearth
|
|
5
5
|
# A class used to represent a query parameter before serialization.
|
6
6
|
class Param
|
7
7
|
# @param [String] name
|
8
|
-
# @param [String, Array<String
|
8
|
+
# @param [String, Array<String>, nil] value (nil)
|
9
9
|
def initialize(name, value = nil)
|
10
10
|
@name = name
|
11
11
|
@value = value
|
@@ -20,7 +20,7 @@ module Hearth
|
|
20
20
|
# @return [String]
|
21
21
|
def to_s
|
22
22
|
if value.is_a?(Array)
|
23
|
-
|
23
|
+
serialize_array(name, value)
|
24
24
|
else
|
25
25
|
serialize(name, value)
|
26
26
|
end
|
@@ -33,7 +33,7 @@ module Hearth
|
|
33
33
|
other.value == value
|
34
34
|
end
|
35
35
|
|
36
|
-
# @return [
|
36
|
+
# @return [Integer]
|
37
37
|
def <=>(other)
|
38
38
|
name <=> other.name
|
39
39
|
end
|
@@ -44,6 +44,10 @@ module Hearth
|
|
44
44
|
value.nil? ? escape(name) : "#{escape(name)}=#{escape(value)}"
|
45
45
|
end
|
46
46
|
|
47
|
+
def serialize_array(name, values)
|
48
|
+
values.map { |v| serialize(name, v) }.join('&')
|
49
|
+
end
|
50
|
+
|
47
51
|
def escape(value)
|
48
52
|
Hearth::HTTP.uri_escape(value.to_s)
|
49
53
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'rspec/expectations'
|
4
4
|
|
5
5
|
# Provides an rspec matcher for CGI.parse to check Float precision.
|
6
|
-
# @api private
|
7
6
|
RSpec::Matchers.define :match_query_params do |expected|
|
8
7
|
match do |actual|
|
9
8
|
return true if actual == expected
|
@@ -19,11 +18,11 @@ RSpec::Matchers.define :match_query_params do |expected|
|
|
19
18
|
|
20
19
|
a.zip(e).each do |a0, e0|
|
21
20
|
# Timestamps can have optional precision.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
|
22
|
+
float = Float(a0)
|
23
|
+
expect(float).to eq(e0.to_f)
|
24
|
+
rescue StandardError
|
25
|
+
expect(a0).to eq(e0)
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
@@ -5,7 +5,7 @@ module Hearth
|
|
5
5
|
# The class must implement #refresh(properties) that sets @identity. The
|
6
6
|
# refresh method will be called when #identity is called and the identity
|
7
7
|
# is nil or near expiration.
|
8
|
-
module
|
8
|
+
module RefreshingIdentityProvider
|
9
9
|
SYNC_EXPIRATION_LENGTH = 300 # 5 minutes
|
10
10
|
ASYNC_EXPIRATION_LENGTH = 600 # 10 minutes
|
11
11
|
|
@@ -13,7 +13,7 @@ module Hearth
|
|
13
13
|
@mutex = Mutex.new
|
14
14
|
end
|
15
15
|
|
16
|
-
# @return [
|
16
|
+
# @return [Identities::Base]
|
17
17
|
def identity(properties = {})
|
18
18
|
if @identity
|
19
19
|
refresh_if_near_expiration!(properties)
|
data/lib/hearth/request.rb
CHANGED
@@ -7,7 +7,7 @@ module Hearth
|
|
7
7
|
# Represents a base request.
|
8
8
|
class Request
|
9
9
|
# @param [URI] uri (URI(''))
|
10
|
-
# @param [IO] body (StringIO.new)
|
10
|
+
# @param [IO, StringIO] body (StringIO.new)
|
11
11
|
def initialize(uri: URI(''), body: StringIO.new)
|
12
12
|
@uri = uri
|
13
13
|
@body = body
|
@@ -16,7 +16,7 @@ module Hearth
|
|
16
16
|
# @return [URI]
|
17
17
|
attr_accessor :uri
|
18
18
|
|
19
|
-
# @return [IO]
|
19
|
+
# @return [IO, StringIO]
|
20
20
|
attr_accessor :body
|
21
21
|
end
|
22
22
|
end
|
data/lib/hearth/response.rb
CHANGED
@@ -5,12 +5,12 @@ require 'stringio'
|
|
5
5
|
module Hearth
|
6
6
|
# Represents a base response.
|
7
7
|
class Response
|
8
|
-
# @param [IO] body (StringIO.new)
|
8
|
+
# @param [IO, StringIO] body (StringIO.new)
|
9
9
|
def initialize(body: StringIO.new)
|
10
10
|
@body = body
|
11
11
|
end
|
12
12
|
|
13
|
-
# @return [IO]
|
13
|
+
# @return [IO, StringIO]
|
14
14
|
attr_accessor :body
|
15
15
|
|
16
16
|
# Replace attributes from other response
|
@@ -26,7 +26,10 @@ module Hearth
|
|
26
26
|
# Resets the response.
|
27
27
|
# @return [Response]
|
28
28
|
def reset
|
29
|
+
# IO does not respond to #truncate but it does respond to #rewind
|
30
|
+
# however it returns an illegal seek error.
|
29
31
|
@body.truncate(0) if @body.respond_to?(:truncate)
|
32
|
+
@body.rewind if @body.respond_to?(:rewind) && !@body.instance_of?(IO)
|
30
33
|
self
|
31
34
|
end
|
32
35
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Hearth
|
4
4
|
module Retry
|
5
5
|
# Adaptive retry strategy for retrying requests.
|
6
|
-
class Adaptive
|
6
|
+
class Adaptive
|
7
7
|
# @param [#call] backoff (ExponentialBackoff) A callable object that
|
8
8
|
# calculates a backoff delay for a retry attempt.
|
9
9
|
# @param [Integer] max_attempts (3) The maximum number of attempts that
|
@@ -22,7 +22,7 @@ module Hearth
|
|
22
22
|
# instance state
|
23
23
|
@client_rate_limiter = ClientRateLimiter.new
|
24
24
|
@retry_quota = RetryQuota.new
|
25
|
-
@capacity_amount =
|
25
|
+
@capacity_amount = 0
|
26
26
|
end
|
27
27
|
|
28
28
|
def acquire_initial_retry_token(_token_scope = nil)
|
@@ -52,12 +52,6 @@ module Hearth
|
|
52
52
|
update_measured_rate
|
53
53
|
|
54
54
|
if is_throttling_error
|
55
|
-
rate_to_use = if @enabled
|
56
|
-
[@measured_tx_rate, @fill_rate].min
|
57
|
-
else
|
58
|
-
@measured_tx_rate
|
59
|
-
end
|
60
|
-
|
61
55
|
# The fill_rate is from the token bucket
|
62
56
|
@last_max_rate = rate_to_use
|
63
57
|
calculate_time_window
|
@@ -138,6 +132,14 @@ module Hearth
|
|
138
132
|
def cubic_throttle(rate_to_use)
|
139
133
|
rate_to_use * BETA
|
140
134
|
end
|
135
|
+
|
136
|
+
def rate_to_use
|
137
|
+
if @enabled
|
138
|
+
[@measured_tx_rate, @fill_rate].min
|
139
|
+
else
|
140
|
+
@measured_tx_rate
|
141
|
+
end
|
142
|
+
end
|
141
143
|
end
|
142
144
|
end
|
143
145
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Hearth
|
4
4
|
module Retry
|
5
5
|
# Standard retry strategy for retrying requests.
|
6
|
-
class Standard
|
6
|
+
class Standard
|
7
7
|
# @param [#call] backoff (ExponentialBackoff) A callable object that
|
8
8
|
# calculates a backoff delay for a retry attempt.
|
9
9
|
# @param [Integer] max_attempts (3) The maximum number of attempts that
|
@@ -15,7 +15,7 @@ module Hearth
|
|
15
15
|
|
16
16
|
# instance state
|
17
17
|
@retry_quota = RetryQuota.new
|
18
|
-
@capacity_amount =
|
18
|
+
@capacity_amount = 0
|
19
19
|
end
|
20
20
|
|
21
21
|
def acquire_initial_retry_token(_token_scope = nil)
|
data/lib/hearth/retry.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'retry/strategy'
|
4
|
-
|
5
3
|
require_relative 'retry/adaptive'
|
6
4
|
require_relative 'retry/capacity_not_available_error'
|
7
5
|
require_relative 'retry/client_rate_limiter'
|
@@ -11,6 +9,21 @@ require_relative 'retry/standard'
|
|
11
9
|
|
12
10
|
module Hearth
|
13
11
|
module Retry
|
14
|
-
|
12
|
+
# Represents a token that can be used to retry an operation.
|
13
|
+
# @!attribute retry_count
|
14
|
+
# The number of times the operation has been retried.
|
15
|
+
# @return [Integer]
|
16
|
+
# @!attribute retry_delay
|
17
|
+
# The delay before the next retry.
|
18
|
+
# @return [Numeric]
|
19
|
+
Token = Struct.new(:retry_count, :retry_delay, keyword_init: true) do
|
20
|
+
# @option args [Integer] :retry_count (0)
|
21
|
+
# @option args [Numeric] :retry_delay (0)
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
self.retry_count ||= 0
|
25
|
+
self.retry_delay ||= 0
|
26
|
+
end
|
27
|
+
end
|
15
28
|
end
|
16
29
|
end
|
data/lib/hearth/structure.rb
CHANGED
@@ -6,15 +6,15 @@ module Hearth
|
|
6
6
|
# Deeply converts the Struct into a hash. Structure members that
|
7
7
|
# are `nil` are omitted from the resultant hash.
|
8
8
|
#
|
9
|
-
# @return [Hash]
|
9
|
+
# @return [Hash, Structure]
|
10
10
|
def to_h(obj = self)
|
11
11
|
case obj
|
12
12
|
when Struct
|
13
13
|
_to_h_struct(obj)
|
14
14
|
when Hash
|
15
15
|
_to_h_hash(obj)
|
16
|
-
when Array
|
17
|
-
obj
|
16
|
+
when Array
|
17
|
+
_to_h_array(obj)
|
18
18
|
when Union
|
19
19
|
obj.to_h
|
20
20
|
else
|
@@ -36,5 +36,9 @@ module Hearth
|
|
36
36
|
hash[key] = to_hash(value)
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
def _to_h_array(obj)
|
41
|
+
obj.collect { |value| to_hash(value) }
|
42
|
+
end
|
39
43
|
end
|
40
44
|
end
|