We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← From Everyday Python to Production Code step 7 of 223
Placement 5/6: Cancel an asyncio Task at Each Stage
Solve this without the hints and you can skim the concurrency track. It is the hardest of the six tests.
Calling an async def function gives you a coroutine, which can pause at
each await. The asyncio event loop runs coroutines in one thread and
switches between them at each pause. A task is a coroutine that the event
loop runs on its own, without anyone awaiting it yet. Cancelling a task
asks it to stop. After task.cancel(), the task sees an
asyncio.CancelledError at its next await. The task can clean up and let the error through, or catch it and
return normally.
The starter's job runs four stages and writes each one to a shared log. The
stages are fetch, parse, store and notify. Before each stage it pauses with
await asyncio.sleep(0), which lets other tasks run.
What to write
Write only drive(reraise: bool, ticks: int) -> list[str]. Leave job,
STAGES and solve as they are. ticks is zero or more.
- Make an empty log and start
job(log, reraise)withasyncio.create_task. Keep the task it returns. - Run
await asyncio.sleep(0)exactlytickstimes. Each one lets the job take one step. - Call
task.cancel()once. - Await the task. If that raises
asyncio.CancelledError, add"propagated"to the log. If it returns a string, add"returned:"followed by that string. - Return the log.
Don't await job directly. That would run the job to the end before drive
could call cancel(). Don't change how the event loop creates tasks either.
CancelledError is a subclass of BaseException, not Exception, so
except Exception does not catch it. Catch asyncio.CancelledError by name.
What the log shows
ticks == 0. You cancel the job before it starts, so it never logs"start"or reaches itsfinally. The log is["propagated"]for both values ofreraise.ticksfrom 1 to 4. The job logs"start"and thenticks - 1stages.cancel()interrupts its next sleep, so it logs"caught", then"cleanup"from itsfinally. Withreraise=Trueit raises the error again, and you add"propagated". Withreraise=Falseit returns"swallowed", and you add"returned:swallowed".ticksof 5 or more. The job has already finished. Callingcancel()on a finished task does nothing and returnsFalse.
solve(True, 3)
# ["start", "fetch", "parse", "caught", "cleanup", "propagated"]
solve(False, 5)
# ["start", "fetch", "parse", "store", "notify", "cleanup", "returned:finished"]
In real code, clean up and raise the error again. asyncio.timeout() and
TaskGroup use cancellation to stop work, and a task that swallows it can
break 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.