Skip to content

Commit b7e8edd

Browse files
committed
Improved support for env.request.timeout and env.request.read_timeout.
1 parent 0a059bc commit b7e8edd

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

lib/async/http/faraday/adapter.rb

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def initialize(...)
119119
super
120120

121121
@timeout = @connection_options.delete(:timeout)
122+
@read_timeout = @connection_options.delete(:read_timeout)
122123

123124
if clients = @connection_options.delete(:clients)
124125
@clients = clients.call(**@connection_options, &@config_block)
@@ -127,6 +128,12 @@ def initialize(...)
127128
end
128129
end
129130

131+
# @attribute [Numeric | Nil] The maximum time to send a request and wait for a response.
132+
attr :timeout
133+
134+
# @attribute [Numeric | Nil] The maximum time to wait for an individual IO operation.
135+
attr :read_timeout
136+
130137
# Close all clients.
131138
def close
132139
# The order of operations here is to avoid a race condition between iterating over clients (#close may yield) and creating new clients.
@@ -181,7 +188,7 @@ def perform_request(env)
181188

182189
request = ::Protocol::HTTP::Request.new(endpoint.scheme, endpoint.authority, method, endpoint.path, nil, headers, body)
183190

184-
with_timeout do
191+
with_timeout(env.request.timeout || @timeout) do
185192
if env.stream_response?
186193
response = env.stream_response do |&on_data|
187194
response = client.call(request)
@@ -213,7 +220,7 @@ def perform_request(env)
213220

214221
def with_client(env)
215222
Sync do
216-
endpoint = Endpoint.new(env.url)
223+
endpoint = Endpoint.new(env.url, timeout: @read_timeout)
217224

218225
if proxy = env.request.proxy
219226
proxy_endpoint = Endpoint.new(proxy.uri)
@@ -229,9 +236,9 @@ def with_client(env)
229236
end
230237
end
231238

232-
def with_timeout(task: Async::Task.current)
233-
if @timeout
234-
task.with_timeout(@timeout, ::Faraday::TimeoutError) do
239+
def with_timeout(timeout = @timeout, task: Async::Task.current)
240+
if timeout
241+
task.with_timeout(timeout, ::Faraday::TimeoutError) do
235242
yield
236243
end
237244
else

releases.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Releases
22

3+
## Unreleased
4+
5+
### Improved support for `timeout` and `read_timeout`.
6+
7+
Previously, only a per-connection `timeout` was supported, but now:
8+
9+
1. `timeout` can be set per request too.
10+
2. `read_timeout` can be set per adapter and is assigned to `IO#timeout` if available.
11+
12+
This improves compatibility with existing code that uses `timeout` and `read_timeout`.
13+
314
## v0.20.0
415

516
- Implement the new response streaming interface, which provides the initial response status code and headers before streaming the response body.

test/async/http/faraday/adapter.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,34 @@ def get_response(url = bound_url, path = "/index", adapter_options: {})
3030
connection&.close
3131
end
3232

33+
with "#timeout" do
34+
it "can set timeout" do
35+
connection = Faraday.new do |builder|
36+
builder.adapter :async_http, timeout: 0.05
37+
end
38+
39+
adapter = connection.builder.app
40+
41+
expect(adapter).to have_attributes(
42+
timeout: be == 0.05
43+
)
44+
end
45+
end
46+
47+
with "#read_timeout" do
48+
it "can set read timeout" do
49+
connection = Faraday.new do |builder|
50+
builder.adapter :async_http, read_timeout: 0.05
51+
end
52+
53+
adapter = connection.builder.app
54+
55+
expect(adapter).to have_attributes(
56+
read_timeout: be == 0.05
57+
)
58+
end
59+
end
60+
3361
with "a local http server" do
3462
include Sus::Fixtures::Async::ReactorContext
3563
include Sus::Fixtures::Async::HTTP::ServerContext

0 commit comments

Comments
 (0)