Feature or enhancement
Add a flag to asyncio.TaskGroup to control whether, if a child task crashes, other should be cancelled or not.
Pitch
Currently asyncio.TaskGroup always cancels all child tasks if one fails. Even if that's the most common use case, I'd like to be able to switch from the current behaviour to prevent child tasks cancellation when one failure occurs and raise an ExceptionGroup with all exceptions raised (only after other tasks completed).
- Excpetions raised in the
async with block still have to cause child tasks to be canceled.
SystemExit and KeyboardInterrupt raised in a child task still cancel other tasks.
Example usage:
async def zero_div():
1 / 0
async def wait_some(d):
await asyncio.sleep(d)
print(f'finished after {d}')
async def main():
async with asyncio.TaskGroup(abort_on_first_exception=False) as tg:
tg.create_task(wait_some(2))
tg.create_task(wait_some(3))
tg.create_task(zero_div())
asyncio.run(main())
# Should print out:
# finished after 2
# finished after 3
# and then raise an `ExceptionGroup` with a `ZeroDivisionError`
Looking at asyncio.TaskGroup source code, it seems that it could be achieved by adding the abort_on_first_exception (or whatever it should be named) flag to the __init__ method and then modify _on_task_done as follow:
class TaskGroup:
def __init__(self, abort_on_first_exception=True):
...
self._abort_on_first_exception = abort_on_first_exception
...
def _on_task_done(self, task):
...
self._errors.append(exc)
is_base_error = self._is_base_error(exc)
if is_base_error and self._base_error is None:
self._base_error = exc
if self._parent_task.done():
# Not sure if this case is possible, but we want to handle
# it anyways.
self._loop.call_exception_handler({
'message': f'Task {task!r} has errored out but its parent '
f'task {self._parent_task} is already completed',
'exception': exc,
'task': task,
})
return
if not self._aborting and not self._parent_cancel_requested:
#comment skipped for brevity
if is_base_error or self._abort_on_first_exception:
self._abort()
self._parent_cancel_requested = True
self._parent_task.cancel()
If it's reasonable to have it in asyncio, I'll be glad to submit a PR for it.
Previous discussion
Post on discuss
Linked PRs
Feature or enhancement
Add a flag to
asyncio.TaskGroupto control whether, if a child task crashes, other should be cancelled or not.Pitch
Currently
asyncio.TaskGroupalways cancels all child tasks if one fails. Even if that's the most common use case, I'd like to be able to switch from the current behaviour to prevent child tasks cancellation when one failure occurs and raise anExceptionGroupwith all exceptions raised (only after other tasks completed).async withblock still have to cause child tasks to be canceled.SystemExitandKeyboardInterruptraised in a child task still cancel other tasks.Example usage:
Looking at
asyncio.TaskGroupsource code, it seems that it could be achieved by adding theabort_on_first_exception(or whatever it should be named) flag to the__init__method and then modify_on_task_doneas follow:If it's reasonable to have it in
asyncio, I'll be glad to submit a PR for it.Previous discussion
Post on discuss
Linked PRs
asyncio.TaskScopeand letasyncio.TaskGroupsubclass it #105011