ADR-0006: Idempotent-only HTTP retries¶
Status: Accepted Date: 2026-04-20
Context¶
OpenStack APIs occasionally return transient 5xx responses or fail with
network errors that resolve on a second try. Generic HTTP-client retry
policies often retry every request, including POST and PATCH. For an
infrastructure CLI, that is dangerous:
- A
POST /serversthat succeeded server-side but lost the response on the network would, on retry, create a second server — silent duplication, billable. - A
PATCHthat partially applied could compose with itself in unpredictable ways depending on the operation semantics.
Decision¶
OrcaClient._request retries only idempotent methods:
GET, HEAD, OPTIONS, PUT, DELETE. POST and PATCH are never
retried automatically — a transient failure surfaces as an error to the
user, who decides whether re-running the command is safe.
Retry policy:
- Up to
MAX_RETRIES = 2attempts after the initial one. - Triggered by
httpxconnect/read timeouts,httpx.NetworkError, and HTTP500/502/503/504. - Exponential backoff with jitter:
random.uniform(0, base * 2**attempt). 429(rate-limit) is handled separately, honouringRetry-Afterper RFC 7231 with aMAX_RATE_LIMIT_WAIT = 60scap.
Consequences¶
- Positive: no risk of duplicated
POST-side resource creation. - Positive: aligns with HTTP RFC 7231 §4.2.2 semantics — operations that the protocol defines as idempotent get the safety net; the rest don't.
- Negative / trade-off: a transient blip during
POST /serverswill surface as an error even though re-running might succeed. Users have to make the call themselves. Documented in--help. - Invariant to protect: any future change to
_requestmust preserveis_idempotent = method.upper() in {"GET","HEAD","OPTIONS","PUT","DELETE"}. A reviewer addingPOSTto the retry set has to update this ADR and explain why duplicates are now acceptable.