Skip to content

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

Closed
kshitijk4poor wants to merge 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-70344-reconnect-watcher
Closed

fix(gateway): prevent reconnect watcher wedge after network-loss fatal error#70919
kshitijk4poor wants to merge 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-70344-reconnect-watcher

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Prevents gateway reconnect watcher from wedging permanently after a network-loss fatal error by respawning the watcher task and using a detach-on-timeout pattern for adapter connect.

Changes

  • gateway/run.py: Add _ensure_reconnect_watcher_running() — detects dead watcher task and respawns it
  • gateway/run.py: Replace asyncio.wait_for with detach-on-timeout pattern in _connect_adapter_with_timeout() — prevents CancelledError-catching adapters from blocking recovery
  • gateway/run.py: Add faulthandler setup at gateway start for post-mortem stack dumps
  • gateway/run.py: Track _reconnect_watcher_task as instance attribute for liveness checks
  • tests/gateway/test_platform_reconnect.py: 8 new tests covering watcher respawn, fatal error integration, and detach-on-timeout

Fixes #70344.

Salvaged from @webtecnica's PR #70530 (commit 2 of 3).

Validation

Before After
test_platform_reconnect 38 passed 46 passed (+8 new)

webtecnica and others added 2 commits July 24, 2026 23:02
…l error (NousResearch#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).
@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
@teknium1

Copy link
Copy Markdown
Contributor

Merged via #70987 — your salvage (with webtecnica's authorship preserved on the core commit) was the base; shannonsands' #69880 startup fix rode along as a separate commit, and we added a POSIX gate on the SIGUSR2 faulthandler registration for Windows. Fixes #70344.

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)

4 participants