From 289259d123763911c8f408e2979d820fd10dc053 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 6 Feb 2025 10:27:18 -0600 Subject: [PATCH] Add human readable error messages for WebSocket PING/PONG timeouts (#10422) --- CHANGES/10422.misc.rst | 3 +++ aiohttp/client_ws.py | 4 +++- aiohttp/web_ws.py | 6 +++++- tests/test_client_ws_functional.py | 1 + tests/test_web_websocket_functional.py | 1 + 5 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 CHANGES/10422.misc.rst diff --git a/CHANGES/10422.misc.rst b/CHANGES/10422.misc.rst new file mode 100644 index 00000000000..7ecb1c0e2e2 --- /dev/null +++ b/CHANGES/10422.misc.rst @@ -0,0 +1,3 @@ +Added human-readable error messages to the exceptions for WebSocket disconnects due to PONG not being received -- by :user:`bdraco`. + +Previously, the error messages were empty strings, which made it hard to determine what went wrong. diff --git a/aiohttp/client_ws.py b/aiohttp/client_ws.py index 757f5f0388f..bfd53ea64bf 100644 --- a/aiohttp/client_ws.py +++ b/aiohttp/client_ws.py @@ -163,7 +163,9 @@ def _ping_task_done(self, task: "asyncio.Task[None]") -> None: self._ping_task = None def _pong_not_received(self) -> None: - self._handle_ping_pong_exception(ServerTimeoutError()) + self._handle_ping_pong_exception( + ServerTimeoutError(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.""" diff --git a/aiohttp/web_ws.py b/aiohttp/web_ws.py index 4f104780c7d..813002e7871 100644 --- a/aiohttp/web_ws.py +++ b/aiohttp/web_ws.py @@ -186,7 +186,11 @@ def _ping_task_done(self, task: "asyncio.Task[None]") -> None: def _pong_not_received(self) -> None: if self._req is not None and self._req.transport is not None: - self._handle_ping_pong_exception(asyncio.TimeoutError()) + 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.""" diff --git a/tests/test_client_ws_functional.py b/tests/test_client_ws_functional.py index 42c705ffb96..190096bbf5e 100644 --- a/tests/test_client_ws_functional.py +++ b/tests/test_client_ws_functional.py @@ -926,6 +926,7 @@ async def handler(request: web.Request) -> NoReturn: assert resp.close_code is WSCloseCode.ABNORMAL_CLOSURE assert msg.type is WSMsgType.ERROR assert isinstance(msg.data, ServerTimeoutError) + assert str(msg.data) == "No PONG received after 0.05 seconds" async def test_close_websocket_while_ping_inflight( diff --git a/tests/test_web_websocket_functional.py b/tests/test_web_websocket_functional.py index 43e98e9f453..6bdd5808362 100644 --- a/tests/test_web_websocket_functional.py +++ b/tests/test_web_websocket_functional.py @@ -841,6 +841,7 @@ async def handler(request: web.Request) -> NoReturn: assert ws.close_code == WSCloseCode.ABNORMAL_CLOSURE assert ws_server_close_code == WSCloseCode.ABNORMAL_CLOSURE assert isinstance(ws_server_exception, asyncio.TimeoutError) + assert str(ws_server_exception) == "No PONG received after 0.025 seconds" await ws.close()