Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python cancellation review: release a permit before propagating task cancellation

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

Task cancellation requests interruption at a coroutine suspension point; resource cleanup still needs a defined ownership scope.

Download Python source kit

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

python
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

Output
['cleanup', 'cancelled', 'next acquired']
permit available: True

Costs 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.

python
cancellation-interview
Storage details