Proxy retries: one user operation can create many attempts
Count retries across layers, bound deadline consumption, and separate safe repetition from duplicate side effects.
On this page
The question for today
What you’ll understand
- Compute a layered worst-case attempt count using retries after the initial attempt.
- Distinguish per-attempt timeout, overall deadline, and active retry budget.
- Explain why a transport failure can leave an application operation's outcome ambiguous.
A retry can rescue a request from a transient failure, but it is additional work at the moment the dependency may already be struggling. Applications, SDKs, gateways, and mesh proxies can each repeat the same operation. Count attempts across the complete path and specify which layer owns retry policy before calling a small local retry count harmless.
Attempts multiply across independent retry layers
One retry means at most two attempts: the original plus one repeat. If a client can make three attempts and each traversed proxy can make two upstream attempts, the downstream can receive as many as six attempts for one original operation. Add another independently retrying layer and the multiplication continues. This is a worst-case upper count assuming every layer reaches its local cap and every attempt reaches the next layer. Eligibility rules, rejections, cancellation, deadlines, and successes can reduce actual work.
Distinguish logical operations, downstream attempts, upstream attempts, and successful completions in telemetry. A proxy receiving one request may start several upstream attempts, while a retried user request can look like a new downstream request unless identifiers preserve the relationship. If the upstream committed an operation and its response was lost, a connection reset does not prove the operation failed. Retrying a write requires application semantics such as an idempotency key and a defined deduplication contract; transport-level retry machinery alone cannot promise exactly-once effects.
A retry budget is not just another timeout
A per-attempt timeout bounds waiting for one try, while an overall deadline limits the logical request's total permitted duration across attempts and backoff. Envoy v1.40.0 documents retries within its overall request timeout, with route and header configuration affecting the policy. An application may have an even shorter deadline that needs propagation and cancellation. A retry started with too little remaining time can consume backend work that cannot produce a useful response. Hedging is different again: concurrent attempts can overlap rather than waiting for an earlier attempt to finish.
A retry budget limits how much extra retry work is allowed relative to an explicitly defined population, often active requests in a proxy's cluster rather than a global count of user operations. Envoy's active-retry resources and retry-budget mechanism have documented scopes; do not interpret them as an automatically coordinated fleet percentage. Backoff and jitter reduce synchronization but do not create capacity. Retry only eligible failures, choose whether a different host is useful, and avoid immediate retries of persistent authorization failures or deterministic validation errors.
Budget the whole failure path
During a controlled failure, compare original-operation rate with attempted backend rate and completed useful work. Record the reason for each retry, consumed deadline, retry overflow, cancellation, and duplicate-effect handling. A falling user-visible error rate may be bought with sharply increased backend CPU and worsen other users' latency. Test a full dependency outage and a slow response after commitment, not only a single quick reset. Coordinate policy changes across layers so disabling one proxy retry does not leave a larger hidden SDK amplification untouched.
The queue lab illustrates changed offered work, not retry execution. Reset, set λ=2 and μ=3, predict the initial four-unit backlog drains in four seconds, then Play or Step. Separately Reset, set λ=4 and μ=3, predict growth of one unit per second, then Play or Step. Treat each unit as a backend attempt only for this synthetic comparison. The instrument does not generate retries, preserve operation IDs, implement backoff, or cancel side effects. Explain how more attempts can cross a service-capacity boundary even when original user demand remains unchanged.
Work it through
Three small policies create eighteen attempts
A client permits two retries, a gateway permits one retry per received attempt, and a source proxy permits two retries per gateway attempt. Suppose all attempts fail quickly and every local cap is exhausted before any deadline.
Convert retries to total attempts: the client allows 3, the gateway 2, and the source proxy 3 for each incoming attempt at that layer.
Multiply: 3×2×3=18 possible backend attempts for one original operation. At 100 original operations/s, the corresponding worst-case offered attempt rate is 1,800/s under these strong assumptions.
For comparison, a separate single-layer model with failure probability 0.2 and two retries has expected attempts 1+0.2+0.04=1.24. Do not substitute this independent steady-probability expectation for the layered all-failure bound.
Local retry counts must be converted to attempts and composed across the actual path. Success, deadlines, and budgets determine how much of the bound is realized.
The living notebook
Explore the model
Interactive lab · queue
Extra attempts can consume the remaining headroom
Reset, set λ=2 and μ=3, predict four initial attempt units drain in four seconds, then Play or Step. Separately Reset, set λ=4 and μ=3, predict one additional waiting unit per second, then Play or Step. The fluid instrument does not generate retries, backoff, hedges, or idempotency behavior.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forRetry work changes backend demand even when the original user-operation rate is unchanged.
Pause & reason
Check your understanding
Your turn
Try it yourself
An overall budget is 200 ms. Two sequential attempts each use 80 ms with a 20 ms backoff between them. A proposed third attempt needs another 40 ms backoff and 80 ms execution. Does that schedule fit?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Count both elapsed attempts and all planned backoff against the overall budget.
Compare with the solution
The first two attempts and their backoff total 80+20+80=180 ms. The proposed third adds 40+80=120 ms, totaling 300 ms, so it cannot fit the 200 ms schedule. A remaining 20 ms does not justify launching an operation requiring the assumed 120 ms path; real cancellation also needs backend cooperation.
Keep the idea
Take it with you
- Compose total attempts across every retrying layer.
- Deadlines, active retry budgets, and backoff control different dimensions.
- Ambiguous transport outcomes require application-level repetition semantics.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.