A careful retry function
Full jitter, Retry-After, and a list of retryable statuses. Status 0 stands for a timeout with no reply.
Many model errors (429, 503, timeouts) go away if you try again later, but a naive retry loop can turn a small hiccup into an outage. This topic builds the full retry from first principles: why immediate retries pile up, exponential backoff, random jitter, Retry-After, retrying only what is retryable, and idempotency.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write is_retryable(status) returning True for 0 (timeout), 408, 429 and 500 to 599, else False. Print it for 0, 200, 400, 429, 503.
Write full_jitter_ms(attempt, base_ms, cap_ms, rand) where rand is a number from 0 up to but not including 1. Return int(rand * (ceiling + 1)) with ceiling = min(cap_ms, base_ms * 2 ** (attempt - 1)). Print the result for attempts 1 to 4 with base 500, cap 8000 and rand = 0.5.
Explain it without notes
Explain the thundering herd and why retrying immediately makes an overload worse.
Why is exponential backoff without jitter not enough, and what does full jitter change?
Which errors should you retry and which not? What is the role of Retry-After?
What is an idempotency key and when do you need one?
Compare what tenacity, p-retry and resilience4j give you with what you built by hand.
Expected output
503, 503, then ok: ok after 3 attempt(s), waited 977 ms
429 with Retry-After: 2: ok after 2 attempt(s), waited 2000 ms
400 bad request: stopped at once: status 400 will not get better by retrying
503 every time: gave up after 4 attempts (last status 503), waited 2302 ms