lib/async/http/client.rb in async-http-0.22.0 vs lib/async/http/client.rb in async-http-0.23.0
- old
+ new
@@ -25,16 +25,17 @@
require_relative 'middleware'
module Async
module HTTP
class Client
- def initialize(endpoint, protocol = nil, authority = nil, **options)
+ def initialize(endpoint, protocol = nil, authority = nil, retries: 3, **options)
@endpoint = endpoint
@protocol = protocol || endpoint.protocol
@authority = authority || endpoint.hostname
+ @retries = retries
@connections = connect(**options)
end
attr :endpoint
attr :protocol
@@ -58,24 +59,42 @@
include Verbs
def call(request)
request.authority ||= @authority
+ attempt = 0
- # As we cache connections, it's possible these connections 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.
- while true
+ begin
+ attempt += 1
+
+ # As we cache connections, it's possible these connections 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.
connection = @connections.acquire
- if response = connection.call(request)
- # The connection won't be released until the body is completely read/released.
- Body::Streamable.wrap(response) do
- @connections.release(connection)
- end
-
- return response
+ response = connection.call(request)
+
+ # The connection won't be released until the body is completely read/released.
+ Body::Streamable.wrap(response) do
+ @connections.release(connection)
+ end
+
+ return response
+ rescue Protocol::RequestFailed
+ # This is a specific case where the entire request wasn't sent before a failure occurred. So, we can even resend non-idempotent requests.
+ @connections.release(connection)
+
+ attempt += 1
+ if attempt < @retries
+ retry
else
- # The connection failed for some reason, we close it.
- connection.close
+ raise
+ end
+ rescue
+ @connections.release(connection)
+
+ if request.idempotent? and attempt < @retries
+ retry
+ else
+ raise
end
end
end
protected