Python3.5 Asyncio - Предотвращение исключения задачи из дампа в стандартный вывод? - PullRequest
0 голосов
/ 05 мая 2018

У меня есть текстовый интерфейс (модуль asciimatics) для моей программы, который использует модули asyncio и discord.py, и иногда, когда мой адаптер Wi-Fi выходит из строя, я получаю исключение, например:

Task exception was never retrieved
future: <Task finished coro=<WebSocketCommonProtocol.run() done, defined at /home/mike/.local/lib/python3.5/site-packages/websockets/protocol.py:428> exception=ConnectionResetError(104, 'Connection reset by peer')>
Traceback (most recent call last):
  File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
    result = coro.throw(exc)
  File "/home/mike/.local/lib/python3.5/site-packages/websockets/protocol.py", line 434, in run
    msg = yield from self.read_message()
  File "/home/mike/.local/lib/python3.5/site-packages/websockets/protocol.py", line 456, in read_message
    frame = yield from self.read_data_frame(max_size=self.max_size)
  File "/home/mike/.local/lib/python3.5/site-packages/websockets/protocol.py", line 511, in read_data_frame
    frame = yield from self.read_frame(max_size)
  File "/home/mike/.local/lib/python3.5/site-packages/websockets/protocol.py", line 546, in read_frame
    self.reader.readexactly, is_masked, max_size=max_size)
  File "/home/mike/.local/lib/python3.5/site-packages/websockets/framing.py", line 86, in read_frame
    data = yield from reader(2)
  File "/usr/lib/python3.5/asyncio/streams.py", line 670, in readexactly
    block = yield from self.read(n)
  File "/usr/lib/python3.5/asyncio/streams.py", line 627, in read
    yield from self._wait_for_data('read')
  File "/usr/lib/python3.5/asyncio/streams.py", line 457, in _wait_for_data
    yield from self._waiter
  File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 296, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/selector_events.py", line 662, in _read_ready
    data = self._sock.recv(self.max_size)
ConnectionResetError: [Errno 104] Connection reset by peer

Это исключение не является фатальным, и, несмотря на это, программа может повторно подключиться - я хочу, чтобы это исключение не сбрасывало в стандартный вывод и не испортило мой текстовый интерфейс.

Я пытался использовать sure_future для обработки, но, похоже, это не сработало. Я что-то упустил:

@asyncio.coroutine
def handle_exception():
    try:
        yield from WebSocketCommonProtocol.run()
    except Exception:
        print("SocketException-Retrying")


asyncio.ensure_future(handle_exception())
#start discord client
client.run(token)

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Ответ, предоставленный Михаилом, вполне приемлем, но я понял, что он не сработает для меня, так как задача, которая вызывает исключение, глубоко скрыта в каком-то модуле, поэтому попытка получить это исключение довольно сложна. Я обнаружил, что вместо этого, если я просто установил пользовательский обработчик исключений для своего асинхронного цикла (цикл создается клиентом Discord):

def exception_handler(loop,context):
   print("Caught the following exception")
   print(context['message'])

client.loop.set_exception_handler(exception_handler)
client.run(token)
0 голосов
/ 05 мая 2018

Task exception was never retrieved - на самом деле это не исключение, распространяемое на стандартный вывод, а сообщение журнала, которое предупреждает вас о том, что вы никогда не получали исключение в одной из своих задач. Вы можете найти детали здесь .

Полагаю, самый простой способ избежать этого сообщения в вашем случае - это извлечь исключение из задачи вручную:

coro = WebSocketCommonProtocol.run()  # you don't need any wrapper
task = asyncio.ensure_future(coro)

try:

    #start discord client
    client.run(token)

finally:

     # retrieve exception if any:
    if task.done() and not task.cancelled():
        task.exception()  # this doesn't raise anything, just mark exception retrieved
...