Task cancellation requests interruption at a coroutine suspension point; resource cleanup still needs a defined ownership scope.
Python cancellation review: release a permit before propagating task cancellation
Operation contract
The interview trace acquires a one-permit semaphore through async with, signals that acquisition and waits on an event. The controller cancels the task only after that signal. A finally clause records local cleanup, then the context manager releases the permit as cancellation leaves the block. The controller observes cancellation and a second task acquires the same permit. The answer should explain this ordering and identify which part changes if cancellation is swallowed.
Failure and ownership boundary
Cancel is a request rather than a synchronous kill. A coroutine doing CPU work without suspension may not observe it promptly. Catching CancelledError and continuing can change shutdown and timeout behavior. Python asyncio shield: caller cancellation does not transfer task ownership, Python asyncio timeout: cancellation and cleanup ownership and Python context managers: clean up on success and failure describe different ways cancellation interacts with ownership.
Working program
import asyncio
async def review():
permit = asyncio.Semaphore(1)
started, blocked = asyncio.Event(), asyncio.Event()
trace = []
async def worker():
async with permit:
started.set()
try:
await blocked.wait()
finally:
trace.append("cleanup")
task = asyncio.create_task(worker())
await started.wait()
task.cancel()
try:
await task
except asyncio.CancelledError:
trace.append("cancelled")
async with permit:
trace.append("next acquired")
print(trace)
print("permit available:", not permit.locked())
asyncio.run(review())Output
['cleanup', 'cancelled', 'next acquired']
permit available: TrueCosts and limits
The fixture owns one blocked worker and one semaphore; no external I/O occurs. For a review exercise, ask where a network client, partial write or background task would live and who must await its final outcome. This trace is not a real-server cancellation or fairness test.
Common Mistakes
- A finally block must not conceal a failure through a return statement.
- Cancelling a task does not undo an already completed external write.
Connected lessons
Python asyncio shield: caller cancellation does not transfer task ownership, Python asyncio timeout: cancellation and cleanup ownership, Python concurrency interview: cancellation must still run cleanup.
