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

nest_asyncio silently breaks async loop exception handling? #57

@chriscline

Description

@chriscline

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions