The timeouts supported are:
:connect_timeout
:write_timeout
(since v0.21.0
):read_timeout
(since v0.21.0
):request_timeout
(since v0.21.0
):operation_timeout
:keep_alive_timeout
:total_timeout
The can be passed as an extra option to the session:
HTTPX.with(timeout: { operation_timeout: 15 }).get("https://google.....")
Timeouts which expire will trigger an error of the HTTPX::TimeoutError
type.
The :connect_timeout
covers the time it takes to establish a TCP connection, and in case it’s a TLS connection, the time it takes to establish a TLS connection.
Timeout expires raise a HTTPX::ConnectionTimeoutError
exception, which subclasses HTTPX::TimeoutError
.
Note: This timeout does not cover the time it takes to perform the DNS hostname resolution.
The :write_timeout
covers the total time it takes to fully send an HTTP request to the server.
Timeout expires raise a HTTPX::WriteTimeoutError
exception.
The :read_timeout
covers the total time it takes to fully read an HTTP response from the server.
Timeout expires raise a HTTPX::ReadTimeoutError
exception.
The :request_timeout
covers the total time it takes to send an HTTP request and read its response fromm the server.
You can use it to combine the 2 timeouts above into 1, and don’t care that much about knowing whether the request failed on writing or reading.
Timeout expires raise a HTTPX::RequestTimeoutError
exception.
The :operation_timeout
is used when waiting for read/write interests on the TCP connection.
Contrary to the timeouts above, which are deadline oriented, :operation_timeout
is used for the individual socket operations, so overall request/response turnaround time may still be quite high, given slow servers can still take advantage of it. If this is important to you, consider instead using :read_timeout
or :write_timeout
instead.
Timeout expires raise a HTTPX::TimeoutError
exception.
The :keep_alive_timeout
is the time after last use of connection (if the connection is persistent) that we will reuse the it for subsequent requests for the same origin. This timeout is therefore reset after every successful response. If the timeout expires when sending a request for the same origin, one of two things will happen:
PING
frame will be sent on the connection to check availability of the connection; if still available, it will be reused, otherwise a new connection will be opened.:total_timeout
The :total_timeout
covers the time to use connections from the moment connection starts, i.e. it cover the time for all requests to be processed. If connnections are still available beyond :total_timeout
, a HTTPX::TotalTimeoutError
exception is raised.
Attention: if you use the :persistent
plugin, the behaviour might result dodgy and unexpected. That’s because the plugin keeps the connections open as much as possible, and :total_timeout
actually covers the connection lifetime, so it’s highly likely the connection lifetime will most times surpass the set timeout. Things will still “appear” to work, because the :persistent
plugin retries requests at least one (to recover from network failures and abruptly closed sockets), so the “total timeout error” will be hidden away from you. But that’s considered a “quirk”, not a “feature”.
Most other libraries only support HTTP/1.1 , which means there’s a direct mapping between the TCP operation to the HTTP interaction (i.e. a read timeout implies one failed reading the HTTP response). This is not true anymore with HTTP/2, where successive socket reads/writes happen during a single HTTP interaction. So this would lead to confusion in some scenarios, so it was replaced by a single op timeout, :operation_timeout
, applicable to both socket reads and writes.
:write_timeout
, :read_timeout
and :request_timeout
are deadline-oriented, in that they meter the time waiting to flush the request to the server, or fully getting a response, or both. This fits the purpose of an HTTP client better, as one doesn’t need to know about which socket, if any, is being used, and it is also less exposed to slow servers of the “dripping” kind.
Resolver options are passed as :resolver_options
, as a hash. The right answer depends of which resolver you’re using:
You can pass a :timeouts
to the :resolver_options
hash, which is documented in the ruby documentation.
As the native resolver reuses the same system resolver options API, the suggestion above still stands.
As the DNS connection is an HTTP(S) connection, all of the above timeouts are to be reused.
Next: Connections