๐Ÿ“ Python

asyncio: Timeouts, Task Cancellation and Graceful Shutdown

P
Author
PyLand Team
๐Ÿ“…
Published
30.06.2026
โฑ๏ธ
Reading time
1 min
๐Ÿ‘๏ธ
Views
605
๐ŸŒณ
Level
Advanced

Three things you absolutely need in production async code.

asyncio.timeout() โ€” painless timeouts (Python 3.11+)

import asyncio

async def slow_operation():
    await asyncio.sleep(10)

async def main():
    try:
        async with asyncio.timeout(3.0):   # 3 seconds max
            await slow_operation()
    except TimeoutError:
        print("Timeout exceeded")

Before Python 3.11 asyncio.wait_for() was used:

async def main():
    try:
        result = await asyncio.wait_for(slow_operation(), timeout=3.0)
    except TimeoutError:
        print("Timeout")

CancelledError โ€” task cancellation

async def worker():
    try:
        while True:
            await do_work()
    except asyncio.CancelledError:
        await cleanup()    # release resources
        raise              # IMPORTANT: always re-raise CancelledError

async def main():
    task = asyncio.create_task(worker())
    await asyncio.sleep(5)
    task.cancel()          # send CancelledError into task
    try:
        await task
    except asyncio.CancelledError:
        print("Task cancelled cleanly")

Rule: in except CancelledError always re-raise. Otherwise the task won’t finish correctly.

Graceful Shutdown โ€” clean termination

import asyncio, signal

async def main():
    loop = asyncio.get_running_loop()
    stop = asyncio.Event()

    def handle_signal():
        print("Got SIGINT, shutting down...")
        stop.set()

    loop.add_signal_handler(signal.SIGINT, handle_signal)
    loop.add_signal_handler(signal.SIGTERM, handle_signal)

    # Main work
    tasks = [asyncio.create_task(worker(i)) for i in range(5)]

    await stop.wait()       # wait for signal

    # Cancel all tasks
    for task in tasks:
        task.cancel()

    # Wait for completion with cleanup
    await asyncio.gather(*tasks, return_exceptions=True)
    print("Shut down cleanly")

asyncio.run(main())

return_exceptions=True in gather() matters: without it the first CancelledError will interrupt waiting for the other tasks.

Your reaction to the article

๐Ÿ’ฌ Comments (0)

๐Ÿ” Sign in to leave a comment
๐Ÿšช Login
๐Ÿ’ญ

No comments yet

Be the first to share your opinion about this article!

๐Ÿ”— Similar

Similar articles

Continue learning with these materials

๐Ÿ“

Event Loop in Python: How asyncio Enables Concurrโ€ฆ

Event loop is the heart of asyncio. It doesn't run code in parallel across multiple...

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 386
๐Ÿ“

run_in_executor and anyio: Sync Libraries in Asynโ€ฆ

Sometimes you need to call a synchronous library from async code without blocking the event...

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 365
๐Ÿ“

Async Context Managers: async with and @asynccontโ€ฆ

Async context managers manage resources in async code โ€” connections, files, transactions.

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 389
๐ŸŽ“ Continue learning

Courses that cover this material

Visit the course to apply this material in practice.

FastAPI: From First Route to an AI-Powered Site Open course curriculum