We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Concurrency with Threads and asyncio step 36 of 56
Retry Within One Shared Deadline
Build the two pieces a request handler needs to keep every retry inside one
time budget. Deadline holds the end time. call_with_deadline retries an
operation until it succeeds, runs out of retries, or runs out of time.
class Deadline:
def __init__(self, budget: float) -> None: ...
def remaining(self) -> float: ...
def expired(self) -> bool: ...
def scope(self, limit: float | None = None) -> asyncio.Timeout: ...
async def call_with_deadline[T](
deadline: Deadline, op: Callable[[], Awaitable[T]], *, retries: int
) -> T
For example, take a 5-second budget and retries=3. An operation that fails
twice with RetryableError and then returns 7 runs three times, and
call_with_deadline returns 7.
Write Deadline
The driver creates each Deadline inside a running event loop.
__init__stores the end time once, asasyncio.get_running_loop().time() + budget.remaining()returns the seconds left. It goes negative after the deadline.expired()returnsTruewhenremaining()is zero or less.scope()returns a newasyncio.Timeout, made withasyncio.timeout_at, that ends at the deadline. Build a new one on every call.scope(limit)ends at whichever comes first, the deadline orlimitseconds from now.limit=0means the scope expires at the nextawait.
Write call_with_deadline
- Make one first attempt and at most
retriesmore.retriesis zero or more. - Before each attempt, check
deadline.expired(). If it isTrue, raiseTimeoutErrorwithout callingop. - Call and await
op()inside a freshdeadline.scope(), and return its result. - If
op()raisesRetryableError, try again straight away, without a pause. When no retries are left, re-raise the lastRetryableError. - Let every other exception propagate without a retry. That includes the
deadline's
TimeoutErrorandCancelledError.
What the driver reports
Keep solve as it is. Some scenarios call call_with_deadline with a test
operation. Others nest deadline.scope(...) blocks around a call that hangs,
and record which except TimeoutError handler ran. The report has these keys:
attempts: how many timesopran. Whenopis slower than the whole budget, this is1, however many retries are allowed.outcome:"ok", or the name of the exception raised.value: the result, or-1.message: the exception's message. The driver reports every timeout message as"".expired: whatdeadline.expired()returns at the end.level: which handler caught the timeout in the nesting scenarios, or"none"."outside"means the handler around theasync withcaught it."inner"and"outer"name the nested block whose handler ran.
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.