Skip to main content
Learning Center
Python Programming

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)

  1. Scheduled by gather
  2. Await sleep(0.01)
  3. Return "A"

fetch("b", 0.02)

  1. Scheduled by gather
  2. Await sleep(0.02)
  3. 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.

Coroutine completion order and gather result order are different. The deadline bounds the whole timeout block, not a fresh second for each fetch. Scheduling and cancellation cleanup can take additional time; this is not a hard real-time completion guarantee.

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

  1. In what order does asyncio.gather return these two results?
  2. What does the asyncio.timeout block bound?
  3. Why should application code normally let CancelledError propagate after cleanup?
Answers
  1. Argument order, ['A', 'B'], regardless of which coroutine completes first.
  2. The elapsed wait for the whole block, including the gathered operations, not each operation independently.
  3. 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.

learning.goultergroup.com

The interactive parts of this page have not loaded. Reading and links still work; reload the page to try again.