[issue44795] asyncio.run does not allow for graceful shutdown of main task
Andreas H.
report at bugs.python.org
Sat Jul 31 08:44:30 EDT 2021
New submission from Andreas H. <ahangauer at gmx.net>:
The issue is that the main task (which was supplied to asyncio.run) has no chance to clean up its "own" sub-tasks and handle
possible exceptions that occur during the sub-task clean up. It prevents a graceful shutdown.
There is no way to prevent the current printing of the "unhandled" exeption, even though the sub-task exception was catched by the main task. (See example below)
-- Current behavior --
When asyncio.run() receives an (unhanded) exception, all tasks are cancelled simultaneously.
If any task generates an exception during its clean-up phase this is printed to the log, even though this exception is handled by the main task.
-- Expected behavior --
asyncio.run() should first cancel the main task, wait for it to complete its shutdown (and possible cancel its own sub-tasks, with exception catching), and *afterwards* cancel the remaining tasks.
-- Example Code --
For instance realize a graceful shutdown of a webserver when SIGTERM signal handler raises a SystemExit exception.
import os
import asyncio
import logging
async def main():
logging.basicConfig(level=logging.INFO)
async def sub_task():
logging.info('sub_task: enter')
try:
while True:
await asyncio.sleep(1)
logging.info('some_task: action')
finally:
logging.info('sub_task: cleanup')
await asyncio.sleep(3)
logging.info('sub_task: cleanup generates exception')
raise ValueError()
logging.info('sub_task: cleanup end')
task = asyncio.create_task(sub_task())
try:
while True:
await asyncio.sleep(1)
except Exception as e:
logging.info(f"Main: exception {repr(e)} received: something went wrong: cancelling sub-task")
task.cancel()
finally:
logging.info("Main: cleanup")
try:
await task
except Exception as e:
logging.info(f"Main: catched exception {repr(e)} from await sub_task")
try:
asyncio.run( main() )
except KeyboardInterrupt:
pass
-- Script Output with Ctrl+C manually generating an KeyboardInterrupt exception --
INFO:root:sub_task: enter
INFO:root:some_task: action
<--- CtrlC pressed here
INFO:root:Main: exception CancelledError() received: something went wrong: cancelling sub-task
INFO:root:Main: cleanup
INFO:root:sub_task: cleanup
INFO:root:sub_task: cleanup generates exception
INFO:root:Main: catched exception ValueError() from await sub_task
ERROR:asyncio:unhandled exception during asyncio.run() shutdown
task: <Task finished coro=<main.<locals>.sub_task() done, defined at D:\Benutzer\projekte\iep\apps\data_player\_signals_test\test.py:10> exception=ValueError()>
Traceback (most recent call last):
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\asyncio\runners.py", line 43, in run
return loop.run_until_complete(main)
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\asyncio\base_events.py", line 574, in run_until_complete
self.run_forever()
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\asyncio\base_events.py", line 541, in run_forever
self._run_once()
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\asyncio\base_events.py", line 1750, in _run_once
event_list = self._selector.select(timeout)
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\selectors.py", line 323, in select
r, w, _ = self._select(self._readers, self._writers, [], timeout)
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\selectors.py", line 314, in _select
r, w, x = select.select(r, w, w, timeout)
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\Benutzer\projekte\iep\apps\data_player\_signals_test\test.py", line 14, in sub_task
await asyncio.sleep(1)
File "C:\Users\z0013xar\AppData\Local\Continuum\anaconda3\lib\asyncio\tasks.py", line 595, in sleep
return await future
concurrent.futures._base.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\Benutzer\projekte\iep\apps\data_player\_signals_test\test.py", line 34, in main
await task
File "D:\Benutzer\projekte\iep\apps\data_player\_signals_test\test.py", line 20, in sub_task
raise ValueError()
ValueError
-- Expected Output --
Same as above but without
"ERROR:asyncio:unhandled exception during asyncio.run() shutdown"
and following traceback
----------
components: asyncio
messages: 398638
nosy: andreash, asvetlov, yselivanov
priority: normal
severity: normal
status: open
title: asyncio.run does not allow for graceful shutdown of main task
type: behavior
_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue44795>
_______________________________________
More information about the Python-bugs-list
mailing list