From 1cd840a1c3f11173d2e7bbb4c0e9a87625e1b523 Mon Sep 17 00:00:00 2001 From: shiftinv <8530778+shiftinv@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:23:37 +0100 Subject: [PATCH] fix: attempt resume on websocket closure with `close_code = 1000` in edge cases (#1241) --- changelog/1241.bugfix.rst | 1 + disnake/gateway.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 changelog/1241.bugfix.rst diff --git a/changelog/1241.bugfix.rst b/changelog/1241.bugfix.rst new file mode 100644 index 0000000000..0765a61e23 --- /dev/null +++ b/changelog/1241.bugfix.rst @@ -0,0 +1 @@ +Attempt to handle abrupt websocket closures on ``aiohttp >= 3.9.0`` and ``python < 3.11.0`` gracefully. diff --git a/disnake/gateway.py b/disnake/gateway.py index b42414b924..ef54d5580b 100644 --- a/disnake/gateway.py +++ b/disnake/gateway.py @@ -687,6 +687,21 @@ def latency(self) -> float: return float("inf") if heartbeat is None else heartbeat.latency def _can_handle_close(self) -> bool: + # bandaid fix for https://github.com/aio-libs/aiohttp/issues/8138 + # tl;dr: on aiohttp >= 3.9.0 and python < 3.11.0, aiohttp returns close code 1000 (OK) + # on abrupt connection loss, not 1006 (ABNORMAL_CLOSURE) like one would expect, ultimately + # due to faulty ssl lifecycle handling in cpython. + # If we end up in a situation where the close code is 1000 but we didn't + # initiate the closure (i.e. `self._close_code` isn't set), assume this has happened and + # try to reconnect. + if self._close_code is None and self.socket.close_code == 1000: + _log.info( + "Websocket remote in shard ID %s closed with %s. Assuming the connection dropped.", + self.shard_id, + self.socket.close_code, + ) + return True # consider this a reconnectable close code + code = self._close_code or self.socket.close_code return code not in (1000, 4004, 4010, 4011, 4012, 4013, 4014)