Cancel all async tasks
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Canceling all asynchronous tasks only makes sense once you define the runtime model, because every async platform does it differently. In Python asyncio, task cancellation is cooperative: you request cancellation, and each task must reach an await point and handle CancelledError correctly before it truly stops.
Cancel Tasks Explicitly in asyncio
In Python, each running asynchronous operation can be wrapped in an asyncio.Task. To cancel many of them, keep references to those tasks and call .cancel() on each one.
Calling .cancel() does not destroy the task instantly. It injects a cancellation request that becomes visible when the task resumes execution at an await point.
Use asyncio.all_tasks() During Shutdown
If you want to cancel nearly everything running in the current loop, asyncio.all_tasks() is useful. The key detail is that you should exclude the task performing the shutdown itself.
This is a common pattern during graceful shutdown in services that need to stop background workers, open connections, or timers before exiting.
Using return_exceptions=True is important here. Without it, the first cancellation exception can interrupt the cleanup sequence and leave the rest of the tasks half-processed.
Cancellation Is Cooperative, Not Forced
This is the part many developers miss. A task can only react to cancellation when it reaches a point where the event loop gets control back. If a task is stuck in CPU-bound work without yielding, it will not stop promptly.
That means good async task design includes:
- regular await points
- cleanup in
except asyncio.CancelledError - resource release in
finallyblocks when necessary
Cancellation is a protocol, not a kill signal. Well-behaved tasks cooperate with it.
Design for Safe Shutdown
In real applications, "cancel all tasks" should usually be part of a broader shutdown plan. You often want to:
- stop accepting new work
- cancel background tasks
- wait for cleanup to finish
- close network or file resources
If tasks manage sockets, files, or transactions, cancellation handling should include cleanup code rather than simply ignoring the exception. Otherwise the application may stop the coroutines while leaving external state inconsistent.
This is why cancellation-aware task code is better than trying to invent a hard kill switch. Async runtimes are built around orderly coordination, and shutdown tends to be most reliable when the tasks participate in their own cleanup.
Common Pitfalls
The most common mistake is calling .cancel() and assuming the task has already stopped. A cancellation request still needs the task to reach a cancellation point.
Another issue is forgetting to await canceled tasks. If you cancel them and exit immediately, cleanup code may never run properly.
People also sometimes call asyncio.all_tasks() and accidentally cancel the task that is trying to coordinate shutdown. Excluding the current task avoids that problem.
Summary
- In Python
asyncio, task cancellation is cooperative rather than immediate. - Cancel specific tasks with
.cancel()and then await them withasyncio.gather(...). - Use
asyncio.all_tasks()during shutdown when you need to cancel most tasks in the loop. - Exclude the current shutdown task so it can finish coordinating cleanup.
- Well-behaved async code should expect cancellation and release resources cleanly.

