1

I have the following example for errorhandling with asyncio:

import asyncio
import logging


def handle_exception(loop, context):
    msg = context.get("exception", context["message"])
    logging.error(f"Caught exception: {msg}")
    logging.warning("Shutting down...")
    asyncio.create_task(shutdown(loop))


async def shutdown(loop, signal=None):
    """Cleanup tasks tied to the service's shutdown."""
    if signal:
        logging.warning(f"Received exit signal {signal.name}...")
    tasks = [t for t in asyncio.all_tasks() if t is not
             asyncio.current_task()]
    [task.cancel() for task in tasks]
    logging.warning(f"Cancelling {len(tasks)} outstanding tasks")
    await asyncio.gather(*tasks, return_exceptions=True)
    loop.stop()


async def bug():
    await asyncio.sleep(10)
    raise ValueError("some error")


def main():
    loop = asyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

    try:
        loop.create_task(bug())
        loop.run_forever()
    finally:
        loop.close()
        logging.warning("shutdown completed")


if __name__ == '__main__':
    main()

This works for me with this "lower level function". But i don't get how to do it without lower level functions. If i try this (rest of the code is the same as above):

async def main():
    loop = asyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

    asyncio.create_task(bug())
    await asyncio.sleep(20)

if __name__ == '__main__':
    asyncio.run(main())

i always get an asyncio.exceptions.CancelledError

How to do this with asyncio.run ?

1 Answer 1

2

You get CancelledError because asyncio.run (like loop.run_until_complete, but unlike loop.run_forever) runs a particular coroutine, and returns its result. When the coroutine is cancelled, the "result" is a CancelledError exception, so that's what asyncio.run() raises. If that doesn't work for you, you can just handle the exception either in main() or in the code that invokes asyncio.run(). For example:

async def main():
    loop = asyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)
    asyncio.create_task(bug())
    try:
        await asyncio.sleep(20)
    except asyncio.CancelledError:
        logging.warning("main cancelled")

Also, when using asyncio.run(), you shouldn't call loop.stop() in shutdown. Stopping the event loop is not allowed when using asyncio.run or loop.run_until_complete and will result in a runtime error complaining of "Event loop stopped before Future completed." The only reason your code doesn't provoke this error is that the main task gets cancelled, so main() gets to complete before the loop stops.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.