def _shutdown_tasks(loop: asyncio.AbstractEventLoop) -> None: """Завершение в случае ошибки. После ошибки происходит отмена всех заданий, чтобы не захламлять сообщение об ошибке множеством сообщений, о том, что результат выполнения задания не был awaited. Идея кода позаимствована из реализации asyncio.app. """ to_cancel = asyncio.all_tasks(loop) if not to_cancel: return for task in to_cancel: task.cancel() loop.run_until_complete(asyncio.gather(*to_cancel, loop=loop, return_exceptions=True)) for canceled_task in to_cancel: if canceled_task.cancelled(): continue if canceled_task.exception() is not None: loop.call_exception_handler( { "message": "unhandled EventBus exception", "exception": canceled_task.exception(), "task": canceled_task, }, ) loop.run_until_complete(loop.shutdown_asyncgens()) loop.run_until_complete(loop.shutdown_default_executor())
def _destroy_loop(loop: asyncio.AbstractEventLoop) -> None: async def murder(future: asyncio.Future[typing.Any]) -> None: # These include _GatheringFuture which must be awaited if the children # throw an asyncio.CancelledError, otherwise it will spam logs with warnings # about exceptions not being retrieved before GC. try: _LOGGER.log(ux.TRACE, "killing %s", future) future.cancel() await future except asyncio.CancelledError: pass except Exception as ex: loop.call_exception_handler({ "message": "Future raised unexpected exception after requesting cancellation", "exception": ex, "future": future, }) remaining_tasks = [ t for t in asyncio.all_tasks(loop) if not t.cancelled() and not t.done() ] if remaining_tasks: _LOGGER.debug("terminating %s remaining tasks forcefully", len(remaining_tasks)) loop.run_until_complete( asyncio.gather(*(murder(task) for task in remaining_tasks))) else: _LOGGER.debug("No remaining tasks exist, good job!") if sys.version_info >= (3, 9): _LOGGER.debug("shutting down default executor") with contextlib.suppress(NotImplementedError): # This seems to raise a NotImplementedError when running with uvloop. loop.run_until_complete(loop.shutdown_default_executor()) _LOGGER.debug("shutting down asyncgens") loop.run_until_complete(loop.shutdown_asyncgens()) _LOGGER.debug("closing event loop") loop.close()