Created on 2017-04-16 18:18 by socketpair, last changed 2017-04-16 18:19 by socketpair.
|msg291763 - (view)||Author: Марк Коренберг (socketpair) *||Date: 2017-04-16 18:18|
How to reproduce: Run the following program: ========================= import asyncio async def handle_connection(reader, writer): try: await reader.readexactly(42) except BaseException as err: print('Interesting: %r.' % err) raise finally: writer.close() loop = asyncio.get_event_loop() coro = asyncio.start_server(handle_connection, '127.0.0.1', 8888) server = loop.run_until_complete(coro) try: loop.run_forever() except KeyboardInterrupt: print('KeyboardInterrupt catched.') server.close() loop.run_until_complete(server.wait_closed()) loop.close() ========================= 0. Python 3.5.2 1. Connect using telnet to localhost and port 888, type one short line and press Enter. 2. Type Ctrl+C in terminal where programw is running. 3. You will see the following output: ========================= ^CKeyboardInterrupt catched. Interesting: GeneratorExit(). Exception ignored in: <coroutine object handle_connection at 0x7fa6a1d91b48> Traceback (most recent call last): File "bug.py", line 12, in handle_connection writer.close() File "/usr/lib/python3.5/asyncio/streams.py", line 306, in close return self._transport.close() File "/usr/lib/python3.5/asyncio/selector_events.py", line 591, in close self._loop.call_soon(self._call_connection_lost, None) File "/usr/lib/python3.5/asyncio/base_events.py", line 567, in call_soon handle = self._call_soon(callback, args) File "/usr/lib/python3.5/asyncio/base_events.py", line 576, in _call_soon self._check_closed() File "/usr/lib/python3.5/asyncio/base_events.py", line 356, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed Task was destroyed but it is pending! task: <Task pending coro=<handle_connection() done, defined at bug.py:4> wait_for=<Future pending cb=[Task._wakeup()]>> ========================= This is almost canonical example of asyncio usage. So I have two questions: 1. Why coroutine is interrupted with GeneratorExit instead of CancelledError ? 2. Why something happend AFTER io loop is closed ? 3. How to code all that right ? I want to close connection on any error. Example provided is simplified code. In real code it looks like: ===== try: await asyncio.wait_for(self._handle_connection(reader, writer), 60) except asyncio.TimeoutError: writer.transport.abort() except asyncio.CancelledError: writer.transport.abort() except Exception: writer.transport.abort() finally: writer.close() =====
components: + asyncio
versions: + Python 3.5