Expand description
The transport boundary: what is retried and what never is.
Moved here from private-gunnar-ops/xtask/src/remote/net.rs (lane T14,
2026-09-21) so the ONE wire implementation of crate::UpCloudApi carries
the same policy every client in that crate already had — and so that crate’s
other HTTP clients (Cloudflare, the health probe) re-use this copy instead of
keeping a second one.
MEASURED 2026-09-20, the live bring-up: GET /1.3/price on the account
answered “error sending request for url” ONCE, and a credential probe turned
that one dropped connection into “provider unavailable”. The token was fine.
The link hiccuped.
§The boundary, and it is not negotiable in the permissive direction
- TRANSPORT — the question never reached the far end, or its answer never came back whole: a refused connection, a reset, a timeout, a name that did not resolve, a TLS handshake that fell over, an HTTP/1.1 framing error mid-flight. Nobody composed that; it is the wire. RETRYABLE, with a bounded budget and a backoff, and every retry is printed so a flaky link can never be mistaken for a healthy one.
- PROTOCOL — the far end understood the question and composed an answer: a status code, a refusal body, a URI this crate built wrong. That is DATA. It is never retried and never softened. A 401 is a revoked credential, a 403 is a scope, a 412 is UpCloud saying out_of_stock, a 404 is an absence — and retrying any of them turns a clear refusal into a hang.
Every client in this crate is built with http_status_as_error(false), so a
status code never even arrives here as an Err: it comes back as an ordinary
response and is judged by the code that asked. That is not an accident, it is
the boundary made structural — the only thing this module can see is the wire.
Structs§
- Budget
- How long the wire is given to stop hiccuping.
Enums§
- Side
- Which side of the boundary an error fell on.
Functions§
- call
- Run
op, retrying ONLY whatsidecallsTransport, saying every retry out loud.whatnames the call in the line that is printed and in the error. - call_
with call, with the clock and the voice injected so the budget can be tested without a test that sleeps.- never_
sent - Did this failure happen BEFORE a single byte of the request went out?
- side
- Classify a
ureqerror. The match is on the VARIANT, not on the text of the message, because a message is a sentence someone can reword and a variant is a decision the library made.