Какой API должна предоставлять библиотека на основе asyncio для обработки критических ошибок? - PullRequest
0 голосов
/ 07 декабря 2018

Я пишу библиотеку, используя asyncio.При некоторых обстоятельствах он обнаруживает ошибку и не может продолжаться.Это не ошибка, у проблемы есть внешняя причина.

Обычный код библиотеки вызовет исключение.Программа завершит работу по умолчанию, но у вызывающей стороны также есть возможность перехватить исключение и выполнить очистку или какой-либо сброс.Это то, что я хочу, но, к сожалению, исключения не работают таким образом в asyncio.Подробнее об этом: https://docs.python.org/3/library/asyncio-dev.html#detect-never-retrieved-exceptions

Каков разумный способ уведомить пользователя асинхронной библиотеки о проблеме?Вероятно, при возникновении ошибки активируется обратный вызов.Пользователь может выполнить необходимую очистку и затем завершить процедуру обратного вызова.

Но что должно быть действием по умолчанию?Отменить текущее задание?Остановить весь цикл событий?Звонок sys.exit?

1 Ответ

0 голосов
/ 09 декабря 2018

В общем, не должно быть необходимости в специфичных для ошибки обратных вызовах.Asyncio полностью поддерживает распространение исключений через await границы внутри сопрограмм, а также через вызовы, такие как run_until_complete, где встречаются синхронизация и асинхронный код.Когда кто-то ожидает вашу сопрограмму, вы можете просто вызвать исключение обычным способом.

Одна ловушка связана с сопрограммами, которые выполняются как «фоновые задачи».Когда такие сопрограммы не работают, что потенциально делает библиотеку непригодной для использования, никто не будет получать уведомления автоматически.Это известный недостаток asyncio (см. здесь для подробного обсуждения), который в настоящее время решается .В то же время вы можете достичь эквивалентной функциональности с помощью кода, подобного следующему:

class Library:
    async def work_forever(self):
        loop = asyncio.get_event_loop()
        self._exit_future = loop.create_future()
        await self._exit_future

    async def stop_working(self):
        self._cleanup()
        self._exit_future.set_result(None)

    async def _failed(self):
        self._cleanup()
        self._exit_future.set_exception(YourExceptionType())

    def _cleanup(self):
        # cancel the worker tasks
        ...

work_forever аналогичен serve_forever, вызову, который может ожидать main()сопрограммы, или даже непосредственно передано asyncio.run().В этом проекте библиотека может обнаружить ошибочное состояние и распространить исключение, или основная программа (предположительно через отдельно порожденную сопрограмму) может запросить ее корректный выход.

...