Asynchronous Workflows
Async Tasks, Deadlines, and Cancellation
Run independent waits concurrently while giving the whole operation a clear deadline and cleanup path.
Lesson 3 of 6 in the recommended order · About 25 min (estimate)
On this page
Outcome
Use gather and timeout to coordinate async work without orphaning tasks.
Why it matters
At this level, code is judged by how safely it changes under load, failure, and team ownership. The technique in this lesson makes an important boundary visible enough to test and review.
Concept
Async improves throughput when work spends time waiting. Create concurrency deliberately, bound it with a deadline, and let cancellation propagate instead of swallowing CancelledError.
Read the code
import asyncio
async def fetch(label, delay):
await asyncio.sleep(delay)
return label.upper()
async def main():
async with asyncio.timeout(1):
values = await asyncio.gather(fetch("a", .01), fetch("b", .02))
print(values)
asyncio.run(main())
Read from the public behavior inward: identify the input boundary, the decision, and the observable result before studying syntax.
Inspect the task timeline after making your prediction
Concurrent waits, ordered results, one deadline
Successful worked example. Schematic stages: spacing is not elapsed time.
fetch("a", 0.01)
- Scheduled by gather
- Await sleep(0.01)
- Return "A"
fetch("b", 0.02)
- Scheduled by gather
- Await sleep(0.02)
- Return "B"
The waits overlap. The shorter sleep normally becomes ready first, but scheduling can delay either task; these are requested delays, not measured completion times.
One shared deadline: 1 second for the timeout block
When both complete within it, gather returns ['A', 'B'] in argument order, even if completion order differs.
Separate hypothetical: the deadline expires
If the block is still awaiting gather when the timeout expires, cancellation reaches unfinished work. Let cancellation propagate after cleanup. The timeout context raises TimeoutError outside the block; the print after the block is not reached. This is not what the successful timeline above depicts.
Predict the output
Predict the exact output before running the example.
Check your prediction
It prints ['A', 'B'] in input order. gather preserves argument order even though task completion timing is independent.
Modify the code
Change one valid input into the nearest invalid or overloaded case. Write down which layer should reject it and what the caller should observe.
Review the change
Keep the failure at the narrowest boundary that owns the rule. Preserve a stable return value or exception contract so callers do not need to inspect implementation details.
Debug the bug
Catching BaseException around a task also catches cancellation and can keep shutdown from finishing. Catch the errors you can handle and allow cancellation to escape.
Try it yourself
Complete the focused implementation and run its deterministic checks.
Python Builder already has a browser event loop, so this exercise ends with top-level await main(). In a local .py script, use the asyncio.run(main()) entry point shown above instead.
Loading this exercise…
Practical challenge (optional)
Add a third operation that exceeds the deadline. Record which cleanup block runs and keep the timeout visible to the caller.
Sign in to track your progress on this exercise.
AI collaboration
Checkpoint
- In what order does
asyncio.gatherreturn these two results? - What does the
asyncio.timeoutblock bound? - Why should application code normally let
CancelledErrorpropagate after cleanup?
Answers
- Argument order,
['A', 'B'], regardless of which coroutine completes first. - The elapsed wait for the whole block, including the gathered operations, not each operation independently.
- Cancellation is the caller's shutdown signal. Swallowing it can make the caller believe work stopped while this task continues.
Sign in to track your progress on this exercise.
Summary and next step
You made the boundary explicit, predicted its behavior, tested a deterministic implementation, and examined its failure mode. Continue to the next lesson to combine this technique with a wider application or production constraint.