How do you gracefully cancel and clean up an asyncio task?

This tests asyncio cooperative cancellation and cleanup. A strong answer covers catching CancelledError at await points, using try/finally or async context managers for cleanup, and re-raising.
What's really being asked
This question probes whether you understand that asyncio cancellation is cooperative, not preemptive. The interviewer wants to see that you know a task only receives a CancelledError at an await point, that cleanup must be async-friendly, and that the event loop requires the exception to propagate so it can finalize the task object and release references.
The full answer
First, explain that calling task.cancel() injects a CancelledError at the next await expression, so the task must actually yield control periodically to be cancellable. Second, describe using a try/finally block or an async context manager to guarantee cleanup runs, such as closing a connection or releasing a lock. Third, emphasize re-raising CancelledError after cleanup so the event loop marks the task as done and wakes any joiners; swallowing it breaks the contract and can leak tasks. Fourth, note that cleanup code itself should not contain blocking synchronous calls or long CPU-bound work without yielding, because that stalls the event loop and delays or prevents cancellation from completing.
The mistakes people make
A major red flag is saying you catch CancelledError and return normally, which leaves the task in a zombie-like state where the event loop thinks it is still active. Another is suggesting thread.kill or os.kill, which reveals confusion between OS threads and asyncio Tasks. Some candidates propose asyncio.shield unconditionally, not realizing shielding prevents cancellation from reaching the coroutine until the shielded block finishes. Also, recommending synchronous cleanup like close() on a blocking socket without running it in a thread shows misunderstanding of the single-threaded event loop and can freeze the application.
What usually comes next
The interviewer might ask how you cancel a task that never awaits, or how you handle cancellation in a background worker that must finish its current unit of work before exiting. They may also ask about asyncio.shield versus asyncio.timeout, or how TaskGroup handles cancellation when one member raises and propagates to siblings.
A concrete example
Imagine a long-running worker that polls a queue with async for message in queue. To make it cancellable, the loop body should await on each network call. Wrap the main loop in try and put connection.close() in finally. If CancelledError fires during await queue.get(), the finally block closes the connection cleanly, then you re-raise CancelledError so the task completes. If you had used a blocking time.sleep inside cleanup instead of await asyncio.sleep, the cancellation would hang the entire loop and prevent other tasks from running.
Interview question
After catching CancelledError in an asyncio task to perform async cleanup, why must you re-raise the exception before returning?
- a.Because asyncio.shield relies on the re-raise to restore the cancellation signal afterward.
- b.Because the event loop uses the exception to finalize the task and wake any joiners.Correct
- c.So the exception bubbles up to the task that called cancel() and interrupts it immediately.
- d.To force the task's finally block to execute before the coroutine exits.
Why? this is the answer
Re-raising CancelledError lets the event loop mark the task as done and unblock any coroutines awaiting it; swallowing it breaks the contract and can leak the task. Option C is tempting because the exception may propagate to an awaiter, but the critical reason to re-raise is to satisfy the event loop's finalization contract, not to interrupt the caller.
Just read this? Test yourself on what you have been reading.
Read the original → docs.python.org
- #asyncio
- #python
- #cancellation
- #concurrency
- #cleanup
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on asyncio — each one lists the topics its interview covers.
See open roles