1

(This is a follow-up question to this one.)


The docs for asyncio say:

If a Future.set_exception() is called but the Future object is never awaited on, the exception would never be propagated to the user code. In this case, asyncio would emit a log message when the Future object is garbage collected.


I want to know whether there's any way to make python forcefully log exceptions regardless of :

  1. Whether or not I awaited the task
  2. Whether or not the task is garbage collected

Basically, I want the ability to fire and forget some background tasks from anywhere in my code, and not worry about await-ing them all the time.

My first-hand async experience was in dart, which does not seem to suffer from this issue.

(Plus, this blatantly violates the zen of python #10).

Dev Aggarwal
  • 7,627
  • 3
  • 38
  • 50

1 Answers1

1

Basically, I want the ability to fire and forget some background tasks from anywhere in my code, and not worry about await-ing them all the time.

If you control the coroutines, the most straightforward way is for the coroutine itself to catch and log the errors. You can automate it using a decorator like this:

def log_exceptions(fn):
    async def run_with_log(*args, **kwds):
        try:
            return await fn(*args, **kwds)
        except Exception as e:
            print "Exception in %s: %s" % (fn.__name__, e)
    return run_with_log

Now, decorating your top-level coroutines with @log_exceptions will give you the requested behavior.

I am not aware of an asyncio switch that does this by default because it would violate the contract of Task (which captures both the return value and the exception raised by the coroutine, if any).

(Plus, this blatantly violates the zen of python #10).

The trio library offers a different take on this, in the form of nurseries, which guarantee not only that the exception will be logged, but that it will be re-raised at a predictable place.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • Thanks. There's also an alternative answer here - https://stackoverflow.com/a/60301541/7061265 – Dev Aggarwal Feb 19 '20 at 13:33
  • Your solution seems to suffer from not being able to catch the original exception in case you do decide to await the task. – Dev Aggarwal Feb 19 '20 at 13:37
  • @DevAggarwal I didn't expect that you'd require _both_ logging and accessing the original exception, but if that's the requirement, then the other answer is an excellent solution. – user4815162342 Feb 19 '20 at 14:13