top of page

Retries

  • Writer: Pradeep P
    Pradeep P
  • 3 days ago
  • 3 min read

Layer 3 · Post 2 of 14

← Previous: Timeouts → Next: Exponential Backoff

Layer 3 — Reliability · Post 27 of 88

Retries recover from transient failures. Done badly, they turn a small outage into a stampede.

What you'll learn

  • Which failures are safe to retry, and which you must not

  • Why retries without a budget and a cap cause retry storms

  • How retries assume idempotency — and why "just retry" is an incomplete design

The idea in one minute

A retry is a second (or third) attempt after a failure you believe is temporary: a timeout, a connection reset, a 503, a packet loss.

Call payments --> timeout | +--> wait a bit --> call again --> 200 OK

You already paid for timeouts. Retries are how you turn "that one blip" into a success the user never sees.

They are also how a 5-second payments blip becomes 3× the traffic just as payments is trying to stand up. Every client retries at once. That is a retry storm.

Why it matters

Networks and multi-tenant neighbors fail in short bursts. Refusing to retry means users eat every blip. Retrying blindly means you amplify load on the sick service — the opposite of Layer 3's job, which is containing failure.

Webhooks (Post 25) retry for days. SQS retries until the message is old. Your HTTP client retries in milliseconds. Same idea, different blast radius.

Interview: say what you retry, how many times, from where (client vs worker), and whether the operation is idempotent. "We retry" without those is a red flag.

How it works

Retry only what is transient.

Safe-ish: connect failures, resets, timeouts if you never saw a response, 429 (with Retry-After), 503, 502 from a proxy that never reached the app.

Do not retry: 400, 401, 403, 404, 409 (usually), most 422s. The second call will fail the same way. Do not retry a 200 with a business error in the body.

Ambiguous: timeout after you sent a POST. The server might have charged the card. You cannot blindly retry unless the POST is idempotent (next post after backoff).

Limits you actually set:

  • Max attempts (often 2–3 on the request path, more in a queue worker).

  • A total deadline inherited from the timeout budget. Three 200 ms tries need ~600 ms plus gaps — that must still fit the gateway.

  • Retry only at one layer when you can. If the SDK, the mesh, and your code all retry, 3×3×3 = 27 calls.

Where to retry:

  • Synchronous request path: few, fast, only for idempotent or clearly unsent calls.

  • Queue / webhook worker: many, with backoff, then a dead-letter queue. The user is not holding a connection.

You will add exponential backoff next so the retries are not a synchronized hammer.

A simple example

The API fetches a user's cart from Redis. The call times out (200 ms). Retrying once is reasonable: Redis blips, the data is a read, doing it twice is safe.

The same API charges a card via Stripe. The HTTP client times out. You do not fire the same charge again from the request thread unless you sent an idempotency key. You persist "charge pending" and let a worker finish it, or you retry with the same key. Otherwise the user sees one spinner and two charges.

Common mistakes

Retrying every HTTP error. 400s and 404s are not transient.

Retries on the hot path with no cap. A timeout cascade: A retries B, B retries C, traffic explodes.

Retrying after a timeout on a write. You do not know if it committed. That is an idempotency problem, not a "try again" problem.

Client, sidecar, and library all retrying. Count the multiplier.

No dead-letter. Infinite retries on a poison message (bad JSON) burn CPU forever.

How this shows up in real systems

  • AWS SDKs, Google Cloud clients, Stripe: retries with backoff built in; you still configure max attempts.

  • SQS / RabbitMQ / Kafka consumers: at-least-once delivery is retries. Consumers must be idempotent.

  • Kubernetes: CrashLoopBackOff is retries with backoff for processes.

  • Envoy / Istio retry policies: per-route, with retry-on conditions (connect-failure, 5xx, reset) so you do not retry 404s.

Recap

  • Retry transient failures; do not retry logic errors.

  • Cap attempts and amplification — storms make outages worse.

  • Writes need idempotency before retries are safe. Backoff decides when the next try happens.

Layer 3 · Post 2 of 14

← Previous: Timeouts → Next: Exponential Backoff

Comments


About Me

DSC_7604.jpg

Hi, I am a software engineer from Bangalore, India. Love spending time on gaming and photography. This website is where I will ocassionally throw what comes to my mind. Hope it is useful or at least entertaining to you. :)

 

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • 500px

© 2023 by Going Places. Proudly created with Wix.com

bottom of page