aio-libs / aiohttp

Asynchronous HTTP client/server framework for asyncio and Python
https://docs.aiohttp.org
Other
15.14k stars 2.02k forks source link

Forcibly closed connection to web.Application results in infinite loop of Exceptions that cannot be caught #3211

Closed rharder closed 2 months ago

rharder commented 6 years ago

Long story short

When the TCP connection to my websocket server is forcibly closed (outside Python's control, such as with TCPView), there is an infinite loop of Exceptions that my user-level code cannot catch.

Expected behaviour

I would expect to get a connection closed message or exception as with other kinds of service interruptions.

Actual behaviour

I get an infinite loop of exceptions that cannot be caught.

Exception in callback BaseSelectorEventLoop._read_from_self()
handle: <Handle BaseSelectorEventLoop._read_from_self()>
Traceback (most recent call last):
  File "C:\Python37-32\lib\asyncio\events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Python37-32\lib\asyncio\selector_events.py", line 125, in _read_from_self
    data = self._ssock.recv(4096)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host

Steps to reproduce

The code below is a smallest-representation of the problem. Run the websocket server on localhost, and connect to it with a client such as the tool at http://www.websocket.org/echo.html?location=ws://localhost:9999 . Then forcibly close the TCP connection using a tool like TCPView to simulate an OS-level event.

#!/usr/bin/env python3
import asyncio
import webbrowser

from aiohttp import web

async def setup():
    app = web.Application()
    app.router.add_get("/", ws_handler)
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, "localhost", port=9999)
    await site.start()

async def ws_handler(request: web.BaseRequest):
    ws = web.WebSocketResponse()
    try:
        await ws.prepare(request)
        await ws.send_str("Welcome to this demo.")
        await ws.send_str("Trying forcing closed this connection with something like TCPView:")
        await ws.send_str("https://docs.microsoft.com/en-us/sysinternals/downloads/tcpview")
        while not ws.closed:
            ws_msg = await ws.receive()
            print("Received:", ws_msg)
    except Exception as ex:
        print("I cannot catch the Exception when connection is forcibly closed.", flush=True)
        print("Exception", ex, flush=True)
        ex.with_traceback()
    finally:
        print("I am never run when connection is forcibly closed.", flush=True)

    return ws

webbrowser.open("http://www.websocket.org/echo.html?location=ws://localhost:9999")
loop = asyncio.get_event_loop()
loop.create_task(setup())
loop.run_forever()

Your environment

BalwinderPalSingh commented 3 years ago
RuntimeError
Traceback (most recent call last)
<ipython-input-38-ba914d8d2dcd> in <module>
     38 loop = asyncio.get_event_loop()
     39 loop.create_task(setup())
---> 40 loop.run_forever()
     41 cv2.imshow("my photo",photo)

c:\users\singhharvin\documents\python36\lib\asyncio\base_events.py in run_forever(self)
    552         self._check_closed()
    553         if self.is_running():
--> 554             raise RuntimeError('This event loop is already running')
    555         if events._get_running_loop() is not None:
    556             raise RuntimeError(

RuntimeError: This event loop is already running

still after running your reproduction code

Dreamsorcerer commented 3 months ago

Think this needs clearer steps to reproduce if this is still an issue.