Skip to content

fix(gateway): prevent reconnect watcher wedge after network-loss fatal error - #70987

Merged
teknium1 merged 4 commits into
mainfrom
fix/gateway-reconnect-watchdog
Jul 24, 2026
Merged

fix(gateway): prevent reconnect watcher wedge after network-loss fatal error#70987
teknium1 merged 4 commits into
mainfrom
fix/gateway-reconnect-watchdog

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

The gateway no longer goes silently deaf after a network loss escalates to a fatal error — the reconnect watcher is (re)started post-escalation, and mixed retryable + non-retryable startup failures no longer kill the process.

Changes

Validation

Targeted gateway reconnect/startup suites green; ruff clean.

Supersedes #70502 (byte-identical core diff, bundled unrelated kanban changes, 163 commits stale).

Fixes #70344

Infographic

gateway-reconnect-watchdog

webtecnica and others added 4 commits July 24, 2026 13:21
…l error (#70344)

Three-part fix for the gateway going silently deaf after a retryable
fatal adapter error (e.g. httpx.ConnectError on Telegram):

1. **Detach-on-timeout in _connect_adapter_with_timeout** — Replaced
   plain asyncio.wait_for with the task-detach pattern used by
   _await_adapter_cleanup_with_timeout. asyncio.wait_for cancels the
   overdue task but then waits for it to exit, so a connect() that
   catches CancelledError can block recovery forever. The detach
   pattern releases the runner at the deadline via
   consume_detached_task_result.

2. **Ensure reconnect watcher always runs after escalation** — Added
   _ensure_reconnect_watcher_running(), called after queueing a
   retryable fatal error. If the reconnect watcher task has died
   (exhausted restart budget, terminal exception), it is respawned
   so queued platforms are never permanently stranded.

3. **Faulthandler at gateway startup** — Enabled faulthandler +
   SIGUSR2 dump to a rotating file under HERMES_HOME/logs/ for
   post-mortem diagnosis of future event-loop freezes.

Tests added for _ensure_reconnect_watcher_running (alive, dead,
not-started, not-running), fatal-error integration (retryable calls
ensure, non-retryable does not), and _connect_adapter_with_timeout
(timeout raises, success returns).
…ailures

When connected_count == 0 and at least one platform failed with a
non-retryable error, the runner exited with GATEWAY_FATAL_CONFIG_EXIT_CODE
(78) even if OTHER platforms failed for merely transient reasons.

Real-world shape (NS-609, hosted instance): WhatsApp enabled but never
paired (non-retryable whatsapp_not_paired) + Telegram TimedOut during
polling startup (retryable) => exit 78 => the gateway either goes
permanently down (supervisors honoring the exit-78 contract via
RestartPreventExitStatus / the s6 finish->125 translation from #51228) or
crash-loops (anything else). Either way Telegram never gets its retry and
the dashboard drops with every exit, so a single unpaired platform plus
one network blip disconnected every channel on the instance.

Now exit 78 is reserved for the case where ALL startup failures are
non-retryable (true config error, nothing to wait for). With mixed
failures the gateway stays alive in degraded state: the reconnect watcher
recovers the retryable platforms and the misconfigured ones stay
fatal-parked and visible in runtime status.
signal.SIGUSR2 and faulthandler.register() don't exist on Windows;
the bare reference raised AttributeError at import time per the
windows-footgun checker. faulthandler.enable() still covers
fatal-error dumps on all platforms.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/gateway Gateway runner, session dispatch, delivery sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on c841846

all good!

@webtecnica

Copy link
Copy Markdown
Contributor

Closing — absorbed by @teknium1 in #70987 (merged dee0b5bf). Salvage of your #70502 via @kshitijk4poor's #70919. Gateway reconnect-watchdog post-escalation fix preserved with your authorship. Supersedes #70502 (byte-identical core diff, but bundled unrelated kanban changes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway silently deaf after generic network loss — reconnect watcher never starts post-escalation (0.19.0)

5 participants