We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Error Handling with Exceptions, Retries and Warnings step 14 of 20
Retry a Fetch with Exponential Backoff
Build a retry helper like the one in Retry Failed Calls with Backoff, and a
solve function that reports what it did. solve fakes the network with a
script of results and records each wait instead of sleeping, so the tests
finish at once.
solve(url="https://pay/charge", script=["transient", "ok"], attempts=3)
-> {"outcome": "ok", "body": b"payload for https://pay/charge", "calls": 2,
"sleeps": [0.5], "type": None, "message": None, "cause_type": None}
Here TransientError is worth retrying, and TerminalError is not.
Write fetch_with_retry
Fill in fetch_with_retry(fetch, url, attempts, sleep), using the starter's
BASE_DELAY = 0.5. The limit counts every attempt, including the first.
- If
attempts < 1, raiseValueError(f"attempts must be at least 1, got {attempts}")before you callfetchorsleep. - Call
fetch(url). If it returns, return its bytes unchanged. - If it raises
TransientErrorand attempts remain, callsleep(BASE_DELAY * 2 ** (n - 1)), wherenis the number of the attempt that failed, counting from 1. Then try again. - If the last allowed attempt raises
TransientError, raiseRetryExhaustedErrorfrom that same exception, with the messagegiving up on {url} after {attempts} attempts. Writeattempt, singular, whenattemptsis 1. - Let any other exception from
fetchescape at once. An exception fromsleepalso escapes, with no further fetch, even if it is aTransientError.
Never sleep after a success or after the last failure. Four failures with
four attempts request the waits [0.5, 1.0, 2.0], 3.5 seconds in all.
Write solve
solve(url, script, attempts) builds a fake fetch and a recording sleep,
then calls fetch_with_retry. When attempts is positive, script has at
least one entry. Each call to the fake fetch uses the next entry, and once
the script runs out it repeats the last one. With n as the call number,
counting from 1:
"transient"raisesTransientError(f"connection reset on call {n}")."terminal"raisesTerminalError(f"404 on call {n}").- Any other entry returns
f"payload for {url}".encode().
The fake fetch counts every call, including the ones that fail. The fake
sleep appends its delay to a list. When attempts is zero or less, the
script may be empty, so read it only inside the fake fetch.
Catch Exception around the call to fetch_with_retry to build the failure
report. Inside fetch_with_retry, catch only TransientError from fetch.
What solve returns
| Key | Value |
|---|---|
"outcome" |
"ok" on success, otherwise "raised" |
"body" |
The returned bytes on success, otherwise None |
"calls" |
The number of fetch calls |
"sleeps" |
The requested waits, in order |
"type" |
The escaping exception's class name, otherwise None |
"message" |
str(exc) on failure, otherwise None |
"cause_type" |
The class name of the exception's __cause__, or None |
The tests show the expected body in a base64 form. Return plain bytes,
and the runner converts them.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.