-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WebSocketResponse does not throw/close when connection is abruptly cut #2309
Comments
At least it logs errors in DEBUG mode (actually, two errors, and one of the with a dot):
|
No progress on this? Is there a workaround one could use? The current situation makes websockets unusable in any cloud environments where connection cuts are pretty common thing. I see this happening quite often in AWS. |
Workaround (the proper solution actually) is sending ping messages from a client. |
Sorry, but isn't connection abruption detection supported by underlying TCP
sockets?
ср, 5 сент. 2018 г., 11:16 Andrew Svetlov <notifications@github.com>:
… Workaround (the proper solution actually) is sending ping messages from a
client.
Unfortunately, browsers don't support WebSocket pings, you have to emulate
them by small regular messages.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2309 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AE4qErU9GgASkaavvOESXhC9K4EXXOKUks5uX4hVgaJpZM4PzyJM>
.
|
Sure.
|
That is understandable. What seems strange to me is that apparently aiohttp can detect that something is wrong since |
Hi, is there currently another way to reliably detect disconnections than doing a manual ping? I observe some messages "socket.send() raised exception." in my console when sending to closed websocket. Is there a way to catch them? I just don't understand why TCP sockets detect disconnection and not websockets in this implementation with the heartbeat parameter. |
I think I isolated instances of such connections:
I was only catching |
I have exactly same issue with WebSocket client. When I drop connection (by the firewall or simply turn off WiFi) while awaiting method receive() of instance ClientWebSocketResponse (and nothing is to be received) the method is awaited (returned) after 15 minutes. Heartbeat is enabled. It can be reproduced with this code: from asyncio import run
from aiohttp import ClientSession
async def main():
async with ClientSession() as session:
async with session.ws_connect('https://echo.websocket.org/',
heartbeat=10) as ws:
print('Connected', ws)
print('Received', await ws.receive())
run(main()) ws.receive() returns CLOSED after 15 minutes (15:30 to 16:10 in tests) after the connection is lost. My environment is Python 3.8.3 and aiohttp 3.7.4.post0. |
The state machine with websockets is somehow fundamentally broken in aiohttp. I don't get it why this is ignored for almost 4 years now. It's the reason I ultimately switched from aiohttp and can't recommend it anymore. As alternative I can recommend Sanic or Starlette. |
I found that the workaround is to create a client with a connector with the parameter From docs:
But the problem I mentioned has nothing to do with SSL servers, it happens when the connection is dropped. So this is just a workaround. |
The connection will not be dropped when you turn off WIFI. TCP establishes a logical circuit between client and server. Even if the physical link layer is cut, the TCP connection is still existed. This could be verified by this command |
Lines 213 to 238 in 184274d
Even if we call Lines 101 to 106 in 184274d
The |
…if network is suddenly interrupted. Related to aio-libs#2309; If we call `receive()` with a unlimited timeout, it will get stuck for long time, because `_pong_not_received` has no way to awake a block coroutine `receive()`. This PR add a `asyncio.Event` to awake this coroutine.
Hi my problem is happen when aiohttp run in ssl mode. It doesn't detect client abrupt disconnect , Does it happen in your case @frederikaalund ? |
It turns out that aiohttp WebSocket code does not recognize if the underlying connection is broken: aio-libs/aiohttp#2309 As a twitch client we know we'll at minimum receive a PING request every 5 minutes even if no other channel updates are happening: https://dev.twitch.tv/docs/irc/#keepalive-messages (I tested this and saw every a ping request always happened between every 4min 1sec to 4min 51sec) If we miss a PING and fail to respond twitch considers the connection closed. Thus we can add a timeout to our websocket receive() call and if we've heard nothing in over 5 minutes our connection is broken and we should perform a reconnect. This has been tested running the bot, and then trying 3 different types of connection breaking: 1) Disabling the network interface on my computer for 5 minutes 2) Suspending laptop and resuming later 3) Dropping related active NAT state on router (similar to rebooting router)
There are a few cases here. We can fix the connection not closing and the exception not being set when the heartbeat times out. If the heartbeat is disabled and the connection is dropped between hosts without any traffic asyncio wont know until the next send fails since receive has no way of knowing the connection has gone away unless there is a RST |
Long story short
This is a continuation of #961 (with some ties to #2283). Apparently, the issue is still valid (I don't know if it was ever really fixed).
I have a single websocket handler. It does two things on connection:
N
bytes over the websocket every secondI connect to this handler through a simple javascript client running in Google Chrome. Everything works as expected: I receive
N
bytes every second, indefinitely.However, when the connection is abruptly cut (by disconnecting the network cable), the websocket sender task takes 15 minutes to stop (even though the heartbeat timeout is only 5 seconds).
Expected behaviour
I would expect the
send_bytes
operation to throw or theasync for msg in ws
loop to terminate/throw.Actual behaviour
The
send_bytes
keep buffering up writes (eventually causing the process to run out of memory and crash). Furthermore, theasync for msg in ws
loop takes 15 minutes to terminate/throw.Steps to reproduce
The websocket server:
The javascript client (wrapped in HTML for browser use):
Note that this only happens for large
N
(around 10000). Everything works fine for sayN = 10
. I don't know why. Maybe some internal caching/buffering is causing this issue?Note that using
await ws.drain()
only stalls the sender. This way, the process doesn't run out of memory but the connection is still in limbo.The practical fix is to query
ws._req.transport.is_closing()
(as pointed out by ttm56p in #2283).I think that aiohttp should handle this internally by whatever means necessary.
It took a long time for me to track down a memory leak to this issue. The writes just kept buffering up. Note that this also happens if you simply let a browser tab sit idle for a long time (apparently, Chrome will stop sending websocket data after a period of inactivity in the tab). In practice, I saw my websocket servers crashing every now and then.
Your environment
Aiohttp 2.2.3 and Python 3.6.1. Google Chrome 61.0.
The text was updated successfully, but these errors were encountered: