DedSec Project

Python asyncio tasks and cancellation — DedSec Project

Python asyncio tasks and cancellation What is happening asyncio runs coroutines cooperatively on an event loop. Blocking disk or CPU work inside a coroutine can still freeze other scheduled…

What is happening

asyncio runs coroutines cooperatively on an event loop. Blocking disk or CPU work inside a coroutine can still freeze other scheduled tasks.

Practical investigation

Pass explicit timeouts for network I/O. When cancellation happens, release acquired resources in finally and propagate CancelledError.

Common traps

Use TaskGroup when supported to own related child tasks and ensure exceptions are not silently ignored.

Adaptable demonstration

python -c 'import asyncio; print(asyncio.__name__)'

Observe cleanup during cancellation

import asyncio

async def worker(started, cleaned):
    try:
        started.set()
        await asyncio.sleep(60)
    finally:
        cleaned.append('released')

async def main():
    started = asyncio.Event()
    cleaned = []
    task = asyncio.create_task(worker(started, cleaned))
    await started.wait()
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        pass
    assert cleaned == ['released']

asyncio.run(main())

The event proves the worker entered its protected region before cancellation, making the fixture deterministic without an arbitrary sleep in the test. The long sleep is cancelled; the fixture does not wait sixty seconds. Awaiting the task retrieves its final cancellation state. A worker that catches cancellation and silently returns can disrupt structured-concurrency ownership.

TaskGroup requires Python 3.11 or later. Keep blocking work out of the event loop, and remember that cancelling an await does not automatically stop arbitrary work already running in a separate thread.

Reference: asyncio task behavior.