Skip to content
This repository has been archived by the owner on Mar 6, 2024. It is now read-only.

nest_asyncio silently breaks async loop exception handling? #57

Open
chriscline opened this issue Jul 16, 2021 · 2 comments
Open

nest_asyncio silently breaks async loop exception handling? #57

chriscline opened this issue Jul 16, 2021 · 2 comments

Comments

@chriscline
Copy link

chriscline commented Jul 16, 2021

The ability to set an asyncio loop exception handler to catch exceptions in tasks appears to be broken when using nest_asyncio. I thought at first this might just be for nested calls, but it happens even in simple un-nested cases where nest_asyncio.apply() has been called. See below for an example. With nest_asyncio.apply, the loop continues running indefinitely with no indication that an exception occurred inside a task; without this line the exception handler is called as expected and terminates the loop.

import asyncio
import nest_asyncio
nest_asyncio.apply()  # comment this out to see "correct" behavior


async def raise_exception():
    await asyncio.sleep(0.5)
    print('About to raise error')
    raise RuntimeError("test")


async def main():
    asyncio.create_task(raise_exception())
    while True:
        await asyncio.sleep(0.3)
        print("Loop still running")


def handleException(loop: asyncio.AbstractEventLoop, context: dict):
    print('Unhandled exception in async task, will stop loop. Exception context:\n%s' % (context,))
    loop.stop()


loop = asyncio.get_event_loop()
loop.set_exception_handler(handleException)
try:
    loop.run_until_complete(main())
except Exception as e:
    print('Caught exception from run')
print('Run finished')

Output with nest_asyncio.apply():

Loop still running
About to raise error
Loop still running
Loop still running
Loop still running
...

Output without nest_asyncio.apply():

Loop still running
About to raise error
Unhandled exception in async task, will stop loop. Exception context:
{'message': 'Task exception was never retrieved', 'exception': RuntimeError('test'), 'future': <Task finished name='Task-2' coro=<raise_exception() done, defined at ...:7> exception=RuntimeError('test')>}
Caught exception from run
Run finished

Similarly, if no exception handler is set: without .apply() a Task exception was never retrieved message is printed to stderr, but with .apply() no such message is printed.

Is there a way to restore typical exception handling? The current behavior makes debugging more complex nested calls with exceptions rather difficult.

I've tested this with identical results on Python 3.8.10 on both Windows and Linux.

@chriscline chriscline changed the title nest_asyncio silently breaks exception handling? nest_asyncio silently breaks async loop exception handling? Jul 16, 2021
@qci-amos
Copy link

in particular, this issue seems to prevent ctrl-c from working correctly. the stdlib version calls _cancel_all_tasks:

https://github.com/python/cpython/blob/b2779b2aa16acb3fd1297ccfe2fe5aaa007f74ae/Lib/asyncio/runners.py#L47

@erdewit
Copy link
Owner

erdewit commented Dec 1, 2021

This fix had to be reverted.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants