-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
asyncio.gather behaves inconsistently when handling KeyboardInterruption/SystemExit #93122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
|
Can you test 3.11 and main branch as the signal handling was changed recently ? |
@kumaraditya303 I have tested on docker 3.11.0b1-bullseye, but still got the same problem. May test main branch later. update: tested on main branch still have the same problem |
|
The traceback message appears at the end of the script after the last line of So I tried to cancel this current task when exception raises, updating your async def main_task():
try:
r = await asyncio.gather(sub_task(), asyncio.sleep(1))
except (SystemExit, KeyboardInterrupt):
# cancel current task
asyncio.current_task().cancel()
# give time to other tasks to run (including me)
await asyncio.sleep(0)
raise
except:
raiseI don't really figure out in detail why but now the traceback message does not appear. I wonder whether something is not missing in I'd like to understand too. |
|
@YvesDup In your case import asyncio
e = KeyboardInterrupt # or SystemExit
async def main_task():
try:
r = await asyncio.gather(sub_task(), asyncio.sleep(1))
except (SystemExit, KeyboardInterrupt):
# cancel current task
asyncio.current_task().cancel()
# give time to other tasks to run (including me)
await asyncio.sleep(0)
print('never reach here')
raise
except:
print('')
raise
async def sub_task():
raise e
if __name__ == '__main__':
try:
asyncio.run(main_task())
except e:
print(f'Handle {e}')There are two independent print('never reach here')
raiseis nerver reached (test by debug). So two try except catch these two interrupt, no traceback anymore, but still very confusing why |
|
|
I'm pretty sure it's not a |
|
Hi @HFrost0 IMO there is also another gap in the documentation about what happens when two or more exceptions raise in tasks. |
|
Hi @YvesDup
I notice you already asked this question link, thank you |
async def main_task():
try:
await asyncio.gather(
sub_task(),
asyncio.sleep(0)
)
except Exception as e:
raise
except BaseException as e:
print(repr(e))if you catch the exception in the |
|
Any update for this? |
|
I'd like to chip in, hope it's fine. With import asyncio
e = KeyboardInterrupt # or SystemExit
async def main_task(use_gather=True):
loop = asyncio.get_running_loop()
tasks = [loop.create_task(sub_task()), loop.create_task(asyncio.sleep(0))]
try:
if use_gather:
await asyncio.gather(*tasks)
else:
await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
except:
for t in tasks:
try:
# Prevent "Task exception was never retrieved"
t.exception()
except:
pass
raise
async def sub_task():
raise e
if __name__ == '__main__':
try:
asyncio.run(main_task(use_gather=False))
except e:
print(f'Handle {e}')I also bumped into the same problem as the I think |
|
This would be a good issue for triagers to test the current behavior and document here. |


Bug report
Here is a minimal example:
This code handles the Interrupt normally as I expected.
But when I add the
asyncio.sleep(0)(can be replaced by other task, not important) intomain_task'sasyncio.gatherThere is an unexpected traceback print out which is really confusing 💦, this traceback indicates that there is
another KeyboardInterrupt raised.
Full traceback
So I go deeply into the
asyncio.run, and write code (a simplifiedasyncio.run) below to figure out what happen.This line will raise another KeyboardInterrupt which is unexpected.
Note that this line is used to cancel all tasks during gracefully shutdown (also in
asyncio.run), and when I changeeto other error likeIndexError(anyBaseException), this code works fine without unexpected another exception.I believe this is related to the
asynciotreatsSystemExitandKeyboardInterruptin different way. For examplein
events.pyMy question is:
asyncio.gatherbehaves inconsistently.KeyboardInterruptdifferently, since the simplest wayto solve this bug is to handle it same as
BaseException.I think user would like to handle all error consistently during the running of a task whether
it's
KeyboardInterruptorBaseException.Even
asynciotreats them in different way (incase really necessary)and
should behave consistently, so I think this is a bug in asyncio.
Your environment
The text was updated successfully, but these errors were encountered: