async-aws 0.2.0 → 0.3.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/Gemfile.lock +16 -13
- data/lib/async/aws.rb +17 -5
- data/lib/async/aws/http_client.rb +102 -0
- data/lib/async/aws/http_handler.rb +46 -2
- data/lib/async/aws/version.rb +1 -1
- metadata +4 -4
- data/lib/async/aws/connection_pool.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4b4634f5e07b319d4e20f927f524e59fea4236693fc38a57d914cba8e616fc8
|
4
|
+
data.tar.gz: 57868e373bbe1137a4f5a0fd38f6727f72eb895ce1a732910e3d5debec1e18b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9acbd7be0847428db25bdc766c184d2c10eb9bd5c6facb72b266389bdcc7d276bf07e99da04cfd959d6522ce1aecf247707061d3b8b1b8f537aacd38b093f01e
|
7
|
+
data.tar.gz: 72f1485b45e5d2b8cd8be02f5ad96dc7161fd8b94e0e4989a95fcd8786e7fc63dd460533ebb1cc88dc2923ca52320dac6ae5030c643b28cb845b3aababecd5dd
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
async-aws (0.
|
4
|
+
async-aws (0.3.0)
|
5
5
|
async-http (~> 0.48)
|
6
6
|
|
7
7
|
GEM
|
@@ -11,14 +11,17 @@ GEM
|
|
11
11
|
console (~> 1.0)
|
12
12
|
nio4r (~> 2.3)
|
13
13
|
timers (~> 4.1)
|
14
|
-
async-http (0.
|
15
|
-
async (~> 1.
|
16
|
-
async-io (~> 1.
|
17
|
-
|
18
|
-
protocol-
|
19
|
-
protocol-
|
20
|
-
|
14
|
+
async-http (0.50.0)
|
15
|
+
async (~> 1.23)
|
16
|
+
async-io (~> 1.27.0)
|
17
|
+
async-pool (~> 0.2)
|
18
|
+
protocol-http (~> 0.13.0)
|
19
|
+
protocol-http1 (~> 0.10.0)
|
20
|
+
protocol-http2 (~> 0.10.0)
|
21
|
+
async-io (1.27.1)
|
21
22
|
async (~> 1.14)
|
23
|
+
async-pool (0.2.0)
|
24
|
+
async (~> 1.8)
|
22
25
|
aws-eventstream (1.0.3)
|
23
26
|
aws-partitions (1.223.0)
|
24
27
|
aws-sdk-core (3.68.1)
|
@@ -43,10 +46,10 @@ GEM
|
|
43
46
|
jmespath (1.4.0)
|
44
47
|
nio4r (2.5.2)
|
45
48
|
protocol-hpack (1.4.1)
|
46
|
-
protocol-http (0.
|
47
|
-
protocol-http1 (0.
|
48
|
-
protocol-http (~> 0.
|
49
|
-
protocol-http2 (0.
|
49
|
+
protocol-http (0.13.0)
|
50
|
+
protocol-http1 (0.10.0)
|
51
|
+
protocol-http (~> 0.13)
|
52
|
+
protocol-http2 (0.10.4)
|
50
53
|
protocol-hpack (~> 1.4)
|
51
54
|
protocol-http (~> 0.2)
|
52
55
|
rake (10.5.0)
|
@@ -78,4 +81,4 @@ DEPENDENCIES
|
|
78
81
|
rspec (~> 3.0)
|
79
82
|
|
80
83
|
BUNDLED WITH
|
81
|
-
2.
|
84
|
+
2.1.2
|
data/lib/async/aws.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'async/http'
|
2
2
|
require 'async/http/internet'
|
3
|
-
require 'async/aws/
|
3
|
+
require 'async/aws/http_client'
|
4
4
|
require 'async/aws/http_handler'
|
5
5
|
require 'async/aws/http_plugin'
|
6
6
|
|
@@ -8,12 +8,24 @@ module Async
|
|
8
8
|
module Aws
|
9
9
|
module_function
|
10
10
|
|
11
|
-
def
|
12
|
-
@
|
11
|
+
def keep_alive_timeout=(arg)
|
12
|
+
@keep_alive_timeout = arg.to_i
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
@
|
15
|
+
def keep_alive_timeout
|
16
|
+
@keep_alive_timeout || 2
|
17
|
+
end
|
18
|
+
|
19
|
+
def connection_pool_size=(arg)
|
20
|
+
@connection_pool_size = arg.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def connection_pool_size
|
24
|
+
@connection_pool_size || 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure(&block)
|
28
|
+
instance_exec(&block)
|
17
29
|
end
|
18
30
|
end
|
19
31
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'async/io/endpoint'
|
4
|
+
require 'async/io/stream'
|
5
|
+
require 'protocol/http/body/streamable'
|
6
|
+
require 'protocol/http/methods'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Aws
|
10
|
+
class HttpClient < ::Protocol::HTTP::Methods
|
11
|
+
attr_accessor :keep_alive_timeout
|
12
|
+
attr_reader :scheme
|
13
|
+
|
14
|
+
ConnectionSpec = Struct.new(:connection, :used_at)
|
15
|
+
|
16
|
+
# Provides a robust interface to a server.
|
17
|
+
# * If there are no connections, it will create one.
|
18
|
+
# * If there are already connections, it will reuse it.
|
19
|
+
# * If a request fails, it will retry it up to N times if it was idempotent.
|
20
|
+
# The client object will never become unusable. It internally manages persistent connections (or non-persistent connections if that's required).
|
21
|
+
# @param endpoint [Endpoint] the endpoint to connnect to.
|
22
|
+
# @param protocol [Protocol::HTTP1 | Protocol::HTTP2 | Protocol::HTTPS] the protocol to use.
|
23
|
+
# @param scheme [String] The default scheme to set to requests.
|
24
|
+
# @param authority [String] The default authority to set to requests.
|
25
|
+
def initialize(endpoint, pool_size: 2, keep_alive_timeout: 5)
|
26
|
+
@endpoint = endpoint
|
27
|
+
@protocol = endpoint.protocol
|
28
|
+
@scheme = endpoint.scheme
|
29
|
+
@authority = endpoint.authority
|
30
|
+
@keep_alive_timeout = keep_alive_timeout
|
31
|
+
@clock_gettime_constant = \
|
32
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
33
|
+
Process::CLOCK_MONOTONIC
|
34
|
+
else
|
35
|
+
Process::CLOCK_REALTIME
|
36
|
+
end
|
37
|
+
@pool = make_pool(pool_size)
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
until @pool.empty?
|
42
|
+
connection_spec = @pool.dequeue
|
43
|
+
connection_spec.connection.close
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def call(request)
|
48
|
+
request.scheme ||= self.scheme
|
49
|
+
request.authority ||= self.authority
|
50
|
+
|
51
|
+
attempt = 0
|
52
|
+
|
53
|
+
# We may retry the request if it is possible to do so. https://tools.ietf.org/html/draft-nottingham-httpbis-retry-01 is a good guide for how retrying requests should work.
|
54
|
+
begin
|
55
|
+
attempt += 1
|
56
|
+
|
57
|
+
# As we cache pool, it's possible these pool go bad (e.g. closed by remote host). In this case, we need to try again. It's up to the caller to impose a timeout on this. If this is the last attempt, we force a new connection.
|
58
|
+
connection_spec = @pool.dequeue
|
59
|
+
if connection_spec.used_at + keep_alive_timeout <= current_time
|
60
|
+
connection_spec.connection.close
|
61
|
+
connection_spec = create_connection_spec
|
62
|
+
end
|
63
|
+
|
64
|
+
# send request
|
65
|
+
response = request.call(connection_spec.connection)
|
66
|
+
|
67
|
+
# The connection won't be released until the body is completely read/released.
|
68
|
+
::Protocol::HTTP::Body::Streamable.wrap(response) do
|
69
|
+
connection_spec.used_at = current_time
|
70
|
+
@pool << connection_spec
|
71
|
+
end
|
72
|
+
|
73
|
+
return response
|
74
|
+
rescue => e
|
75
|
+
@pool << connection_spec if connection_spec
|
76
|
+
raise e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def current_time
|
83
|
+
Process.clock_gettime(@clock_gettime_constant)
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_connection_spec
|
87
|
+
ConnectionSpec.new(
|
88
|
+
@protocol.client(@endpoint.connect),
|
89
|
+
current_time
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def make_pool(size)
|
94
|
+
Async::Queue.new.tap do |queue|
|
95
|
+
size.times do
|
96
|
+
queue << create_connection_spec
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,17 +1,53 @@
|
|
1
1
|
module Async
|
2
2
|
module Aws
|
3
3
|
class HttpHandler < ::Seahorse::Client::Handler
|
4
|
+
def self.clients
|
5
|
+
@clients ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.with_configuration(**kwargs)
|
9
|
+
Class.new(self).tap do |klass|
|
10
|
+
klass.connection_pool_size = kwargs.fetch(
|
11
|
+
:connection_pool_size, Async::Aws.connection_pool_size
|
12
|
+
)
|
13
|
+
klass.keep_alive_timeout = kwargs.fetch(
|
14
|
+
:keep_alive_timeout, Async::Aws.keep_alive_timeout
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.connection_pool_size
|
20
|
+
@connection_pool_size ||= Async::Aws.connection_pool_size
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.connection_pool_size=(value)
|
24
|
+
@connection_pool_size = value.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.keep_alive_timeout
|
28
|
+
@keep_alive_timeout ||= Async::Aws.keep_alive_timeout
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.keep_alive_timeout=(value)
|
32
|
+
@keep_alive_timeout = value.to_i
|
33
|
+
end
|
34
|
+
|
4
35
|
def call(context)
|
5
36
|
req = context.http_request
|
6
37
|
resp = context.http_response
|
38
|
+
endpoint = Async::HTTP::Endpoint.parse(req.endpoint.to_s)
|
7
39
|
|
8
40
|
begin
|
41
|
+
client = client_for(endpoint)
|
9
42
|
headers_arr = req.headers.reject do |k, v|
|
10
43
|
k == 'host' || k == 'content-length'
|
11
44
|
end
|
12
|
-
|
13
|
-
|
45
|
+
buffered_body = Async::HTTP::Body::Buffered.wrap(req.body)
|
46
|
+
request = ::Protocol::HTTP::Request.new(
|
47
|
+
client.scheme, endpoint.authority, req.http_method, endpoint.path,
|
48
|
+
nil, headers_arr, buffered_body
|
14
49
|
)
|
50
|
+
response = client.call(request)
|
15
51
|
body = response.read
|
16
52
|
resp.signal_headers(response.status.to_i, response.headers.to_h)
|
17
53
|
resp.signal_data(body)
|
@@ -23,6 +59,14 @@ module Async
|
|
23
59
|
|
24
60
|
Seahorse::Client::Response.new(context: context)
|
25
61
|
end
|
62
|
+
|
63
|
+
def client_for(endpoint)
|
64
|
+
self.class.clients[endpoint.hostname] ||= ::Async::Aws::HttpClient.new(
|
65
|
+
endpoint,
|
66
|
+
pool_size: self.class.connection_pool_size,
|
67
|
+
keep_alive_timeout: self.class.keep_alive_timeout
|
68
|
+
)
|
69
|
+
end
|
26
70
|
end
|
27
71
|
end
|
28
72
|
end
|
data/lib/async/aws/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien D.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-http
|
@@ -130,7 +130,7 @@ files:
|
|
130
130
|
- lib/async-aws.rb
|
131
131
|
- lib/async/aws.rb
|
132
132
|
- lib/async/aws/all.rb
|
133
|
-
- lib/async/aws/
|
133
|
+
- lib/async/aws/http_client.rb
|
134
134
|
- lib/async/aws/http_handler.rb
|
135
135
|
- lib/async/aws/http_plugin.rb
|
136
136
|
- lib/async/aws/version.rb
|
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
157
|
- !ruby/object:Gem::Version
|
158
158
|
version: '0'
|
159
159
|
requirements: []
|
160
|
-
rubygems_version: 3.
|
160
|
+
rubygems_version: 3.1.2
|
161
161
|
signing_key:
|
162
162
|
specification_version: 4
|
163
163
|
summary: Async AWS SDK adapter for `socketry/async` framework
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Async
|
2
|
-
module Aws
|
3
|
-
class ConnectionPool
|
4
|
-
def initialize(connection_limit: nil)
|
5
|
-
@clients = {}
|
6
|
-
@connection_limit = connection_limit
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(method, url, headers = [], body = nil)
|
10
|
-
endpoint = ::Async::HTTP::Endpoint.parse(url)
|
11
|
-
client = client_for(endpoint)
|
12
|
-
|
13
|
-
request_body = \
|
14
|
-
case body
|
15
|
-
when ::Aws::Query::ParamList::IoWrapper
|
16
|
-
::Async::HTTP::Body::Buffered.wrap(body.instance_variable_get(:@io))
|
17
|
-
else
|
18
|
-
::Async::HTTP::Body::Buffered.wrap(body)
|
19
|
-
end
|
20
|
-
request = ::Protocol::HTTP::Request.new(
|
21
|
-
endpoint.scheme, endpoint.authority, method, endpoint.path, nil, headers,
|
22
|
-
request_body
|
23
|
-
)
|
24
|
-
|
25
|
-
client.call(request)
|
26
|
-
end
|
27
|
-
|
28
|
-
def client_for(endpoint)
|
29
|
-
@clients[endpoint] ||= ::Async::HTTP::Client.new(
|
30
|
-
endpoint, endpoint.protocol, endpoint.scheme, endpoint.authority,
|
31
|
-
retries: 3, connection_limit: @connection_limit
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
def close
|
36
|
-
@clients.each_value(&:close)
|
37
|
-
@clients.clear
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|