I have a new research project, called “asyncbis” here. The purpose of this project is to determine how and if level cancellation (as opposed to the current “edge” cancellation) and full-fledged cancel scopes could be introduced to asyncio, and how badly third party asyncio projects would break with these changes. The cancellation model is intended to conform to that of Trio and AnyIO.
Altered behavior
First and foremost, this modifies task spawning so that all tasks (except for the “root” task, spawned automatically) belong to a task group. If any such “background” task raises an exception, it will cause the root task group to be cancelled, and the exception propagated to the run() caller. If this is behavior is unwanted, exceptions should be caught and handled in the target coroutine directly.
Task groups now have a cancel() method which sets the task group’s cancel scope into a cancelled state. Tasks can still be spawned, but they will raise CancelledError at the first yield point, and any yield point unless inside a shielded cancel scope.
The existing shield() function was also modified to run the target awaitable directly in the host task under a shielded cancel scope, rather than creating a separate task which could be subject to cancellation if the event loop is shut down. This has the effect of also protecting the host task from cancellation during the call.
Python 3.11 introduced the timeout() and timeout_at() context managers to asyncio. These are essentially cancel scopes without level cancellation or shielding. This project adds level cancellation and shielding capabilities to said context managers.
Shutdown behavior was also altered so that the root task group is cancelled as a result of the first SIGINT or SIGTERM (which is now handled similarly), rather than cancelling all tasks directly. This allows tasks, and entire task groups a chance to react to the cancellation by performing a finalization step inside a shielded cancel scope. With the second such signal to arrive, however, it performs a hard shutdown, as before.
Future directions
If the initial, “research” phase is deemed successful, this could be spun into a full-fledged, alternate implementation. Building these features on top of rsloop could be an option, as it looks like a promising new alternative event loop implementation.
An AnyIO backend for this is also on the roadmap.