From 909731dc715a692daad3483b59f1e8f9f743e640 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:41:58 +0530 Subject: [PATCH] refactor(discord): state the dispatch-liveness rationale once The #109521 explanation (socket_event_type fires for every parsed DISPATCH frame and is not debug-gated unlike on_socket_raw_receive; op-11 ACKs carry no event type) was written out four times: knob init, stamp init, the on_socket_event_type handler, and _read_websocket_health. Keep the authoritative paragraph on the handler that actually stamps, and point the other three sites at it so a future edit has one place to go. Drop the math.isfinite(event_silence) half of the silence guard. Both operands are our own perf_counter floats, so their difference cannot be non-finite; the ack_age guard is different because _last_ack comes from discord.py. math stays imported for the remaining finiteness checks. --- plugins/platforms/discord/adapter.py | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/plugins/platforms/discord/adapter.py b/plugins/platforms/discord/adapter.py index 9847284a7f..c619880f81 100644 --- a/plugins/platforms/discord/adapter.py +++ b/plugins/platforms/discord/adapter.py @@ -1071,16 +1071,11 @@ class DiscordAdapter(DiscordMediaMixin, BasePlatformAdapter): self._max_latency_seconds = self._finite_positive_config_float( "websocket_max_latency_seconds", 30.0, ) - # Dispatch-side liveness (#109521 incident 2): an ESTAB socket can keep ACKing - # heartbeats (op 11, no event type) while zero DISPATCH events are parsed, so every - # transport-side sample reads healthy for hours. ``socket_event_type`` fires for every - # parsed DISPATCH frame and is NOT gated behind ``enable_debug_events`` (unlike - # ``on_socket_raw_receive`` — verified against discord.py 2.7.1 ``gateway.py``: - # ``received_message`` calls ``self._dispatch('socket_event_type', event)`` before the - # op-code switch). 0 disables this dimension alone; ack-age/latency still guard. - # Default 4h mirrors the field-proven operator bound from the incident report; quiet - # guilds can go hours without a single DISPATCH event (typing/reaction/presence), so - # a short bound would force reconnect loops on healthy-but-idle installs (#109782). + # Dispatch-side liveness bound (#109521; rationale on ``on_socket_event_type``). + # 0 disables this dimension alone; ack-age/latency still guard. Default 4h mirrors the + # field-proven operator bound from the incident report; quiet guilds can go hours + # without a single DISPATCH event, so a short bound would force reconnect loops on + # healthy-but-idle installs (#109782). self._event_max_silence_seconds = self._finite_positive_config_float( "websocket_event_max_silence_seconds", 14400.0, ) @@ -1088,10 +1083,9 @@ class DiscordAdapter(DiscordMediaMixin, BasePlatformAdapter): self._liveness_notification_task: Optional[asyncio.Task] = None # True while disconnect() intentionally closes discord.py (done callback: shutdown vs crash). self._disconnecting = False - # Last DISPATCH frame's monotonic stamp (#109521): ticked by ``on_socket_event_type`` - # (fires for every parsed DISPATCH event, not debug-gated) and read by the liveness - # probe's ``event_silence`` dimension. ``None`` means "no event yet on this connection" - # and is not treated as silence (on_ready often arrives in bursts). + # Last DISPATCH frame's monotonic stamp, ticked by ``on_socket_event_type`` (see its + # rationale) and read by ``_read_websocket_health``. ``None`` = no event yet on this + # connection, which is not silence. self._last_dispatched_event_monotonic: Optional[float] = None self._missed_message_backfill_task: Optional[asyncio.Task] = None from hermes_constants import get_hermes_home @@ -1287,11 +1281,15 @@ class DiscordAdapter(DiscordMediaMixin, BasePlatformAdapter): @self._client.event async def on_socket_event_type(event_type: str): - # Dispatch-side liveness stamp (#109521): discord.py dispatches this for every - # parsed DISPATCH frame on every connection — no ``enable_debug_events`` needed - # (unlike ``on_socket_raw_receive``). Heartbeat ACKs (op 11) return before the - # dispatch, so an ACKing-but-deaf socket leaves this stamp frozen while every - # transport-side check reads healthy. + # Dispatch-side liveness stamp (#109521 incident 2): an ESTAB socket can keep + # ACKing heartbeats (op 11, no event type) while zero DISPATCH events are parsed, + # so every transport-side sample reads healthy for hours. discord.py dispatches + # ``socket_event_type`` for every parsed DISPATCH frame on every connection and it + # is NOT gated behind ``enable_debug_events`` (unlike ``on_socket_raw_receive`` — + # verified against discord.py 2.7.1 ``gateway.py``: ``received_message`` calls + # ``self._dispatch('socket_event_type', event)`` before the op-code switch). + # Heartbeat ACKs return before that dispatch, so an ACKing-but-deaf socket leaves + # this stamp frozen while every transport-side check reads healthy. adapter_self._last_dispatched_event_monotonic = time.perf_counter() @self._client.event @@ -1693,12 +1691,14 @@ class DiscordAdapter(DiscordMediaMixin, BasePlatformAdapter): # explicit 0 disables this dimension alone and ack-age/latency keep guarding (the #109782 # regression put the knob in the probe's all-or-nothing startup guard, killing the whole # watchdog). ``None`` = no DISPATCH event yet on this connection: not silence (the - # not_ready check above still covers the pre-ready window). + # not_ready check above still covers the pre-ready window). Why the stamp is trustworthy: + # see ``on_socket_event_type``. No finiteness guard here: both operands are our own + # perf_counter floats (``ack_age`` differs — ``_last_ack`` is discord.py's). if self._event_max_silence_seconds > 0: last_event = self._last_dispatched_event_monotonic if last_event is not None: event_silence = time.perf_counter() - last_event - if not math.isfinite(event_silence) or event_silence > self._event_max_silence_seconds: + if event_silence > self._event_max_silence_seconds: return False, "event_silence" return True, "healthy"