-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Handle PONG messages before closing connection due to heartbeat timeout #10544
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
base: master
Are you sure you want to change the base?
Changes from 10 commits
c1878fa
1f0f1aa
77d624d
a89f86f
365fdf7
605f600
48f77af
73ecb05
7768ff5
8a591d0
5d7c76e
290fa31
3439d1c
85696f3
4d9ebf0
8f3de6f
6e9e13f
29a439e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Check for PONG before closing connection for missing PONG -- by :user:`mstegmaier`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,12 +185,43 @@ | |
self._ping_task = None | ||
|
||
def _pong_not_received(self) -> None: | ||
"""Callback for when no PONG was received after self._pong_heartbeat seconds""" | ||
if self._req is not None and self._req.transport is not None: | ||
self._handle_ping_pong_exception( | ||
asyncio.TimeoutError( | ||
f"No PONG received after {self._pong_heartbeat} seconds" | ||
loop = self._loop | ||
if loop is not None: | ||
pong_not_received_task = loop.create_task(self._pong_not_received_coro()) | ||
|
||
else: | ||
self._handle_ping_pong_exception( | ||
asyncio.TimeoutError( | ||
f"No PONG received after {self._pong_heartbeat} seconds" | ||
) | ||
) | ||
|
||
async def _pong_not_received_coro(self) -> None: | ||
"""Coroutine to check for pending PONG when no PONG was received after self._pong_heartbeat seconds""" | ||
reader = self._reader | ||
assert reader is not None | ||
try: | ||
async with async_timeout.timeout(1): | ||
msg = await reader.read() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible for a user to catch the exception or anything and avoid the connection close? If it is, then this would break their code, as we've now read a message that they should be processing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is the same point as #10544 (review) |
||
self._reset_heartbeat() | ||
if msg.type is not WSMsgType.PONG: | ||
ws_logger.warning( | ||
f"Received {msg} while waiting for PONG. It seems like you haven't called `receive` within {self._pong_heartbeat} seconds." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't exactly accurate. The user's code could be reading a message with receive() every second, but if there are more than pong_heartbeat messages between PONGs, then it would still get tripped up here. |
||
) | ||
return | ||
except asyncio.TimeoutError: # We still did not receive a PONG | ||
pass | ||
except Exception as exc: | ||
self._exception = exc | ||
self._set_closing(WSCloseCode.ABNORMAL_CLOSURE) | ||
await self.close() | ||
return | ||
self._handle_ping_pong_exception( | ||
asyncio.TimeoutError( | ||
f"No PONG received after {self._pong_heartbeat} seconds" | ||
) | ||
) | ||
|
||
def _handle_ping_pong_exception(self, exc: BaseException) -> None: | ||
"""Handle exceptions raised during ping/pong processing.""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear this would have a noticeable benefit to the user. They are likely to still get the same result regardless, this just seems to catch a (probably rare) edge case that might reduce the frequency of connection closes very slightly.