HTTP2::Client::Timeouts
Per-operation deadlines. Nil disables the corresponding timeout.
connect covers DNS and TCP dialing, read covers the TLS and
HTTP/2 handshakes (for https origins, the TLS handshake itself;
then, for both schemes, the wait for the peer's SETTINGS after
dialing) and each response-header wait, write covers transport
writes, and idle covers a blocked response-body read or trailer
wait. There is no persistent socket-level read timeout, so a
quiet-but-healthy connection (an idle pooled connection, a
long-lived SSE or long-poll stream) is never killed merely for
going quiet between waits. Liveness on an established connection is
keepalive's job instead: connection_configuration's
keepalive_interval/keepalive_timeout (30 seconds / 10 seconds by
default for HTTP2::Client) periodically PINGs the peer and fails
the connection if it stops answering; supply a configuration with
keepalive_interval: nil to disable it.
idle also bounds a Response that the caller abandons — never
reads, never closes — but ONLY while its body is actually pinning
connection-window credit (unread buffered bytes sitting in it).
Each time idle elapses with unread buffered data present and no
bytes consumed since the previous check, the response's stream is
canceled: flow-control credit for that buffered data is returned,
RST_STREAM is sent, and the body is left with a terminal error, so
a later read raises that specific error (e.g. RequestTimeoutError
here). A caller's own Response#close also makes a later read
raise rather than return a silent EOF, but with a generic
IO::Error ("Closed stream") instead of a stream's own terminal
error — a library-initiated reclamation stays distinguishable from
a caller's own graceful stop by exception type, not by whether
reading raises at all. If any bytes WERE consumed in
that window, the deadline simply re-arms, so a slow-but-active
reader is never killed. A quiet stream with an EMPTY buffer — an
SSE or long-poll response waiting between events, a successful
CONNECT tunnel sitting quiet while the app uploads — pins no credit
and keeps running indefinitely: the "never killed merely for going
quiet" contract above still holds for it. Set idle: nil to
disable this safety net along with the per-read/trailer timeout it
shares the setting with.
stream_slot is the pool-wide request-capacity budget. A request
first tries every eligible connection and may start one shared,
demand-driven expansion dial. nil (the default) performs that
growth but raises PoolSaturatedError as soon as the pool can make
no further progress. A span waits up to that long for any connection
to gain capacity, for an expansion dial, or for a SETTINGS increase.
Cancellation and client close interrupt the wait. Atomic logical
reservations do not consume stream IDs while waiting, and opening on
one connection does not serialize opening on another connection.