Skip to content

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

Closed
webtecnica wants to merge 2 commits into
NousResearch:mainfrom
webtecnica:fix/70344-gateway-reconnect-wedge
Closed

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

Conversation

@webtecnica

Copy link
Copy Markdown
Contributor

Problem

The gateway goes silently deaf after a retryable fatal adapter error (e.g. httpx.ConnectError on Telegram). gateway_state shows running but platforms.telegram.state never returns to connected. No messages are processed until an external restart. The reconnect watcher never starts after the fatal error escalation.

Root causes:

  1. _connect_adapter_with_timeout used asyncio.wait_for(), which can hang forever if the adapter's connect() catches CancelledError - wedging the watcher.
  2. The reconnect watcher task, if it dies (exhausts restart budget from _spawn_supervised), is never respawned when platforms get queued.
  3. No diagnostics exist to capture thread/task stacks when the event loop freezes.

Changes

1. Detach-on-timeout in _connect_adapter_with_timeout

Replaced asyncio.wait_for() with the task-detach pattern from _await_adapter_cleanup_with_timeout.

2. _ensure_reconnect_watcher_running() + call from fatal handler

Ensures the reconnect watcher is always alive after queueing a retryable fatal error.

3. Faulthandler at gateway startup

faulthandler.enable() + SIGUSR2 dump to logs for post-mortem diagnosis.

Tests Added

  • 4 tests for _ensure_reconnect_watcher_running
  • 2 tests for fatal error integration
  • 2 tests for detach-on-timeout

Testing

All existing and new tests pass (59 total).

Closes #70344

Hermes Agent added 2 commits July 23, 2026 23:13
…asks (NousResearch#69787)

Docs promise board default_workdir is inherited by every new task, but
CLI and tool-created tasks defaulted to 'scratch' workspace regardless
of the board setting. The dashboard was the only path that honoured
default_workdir.

Root cause:
- hermes_cli/kanban.py --workspace default='scratch' always passed an
  explicit scratch kind, bypassing the board default_workdir
- hermes_cli/kanban_db.py create_task only resolved default_workdir for
  already-persistent kinds (dir/worktree), never for the default scratch
- tools/kanban_tools.py kanban_create forced workspace_kind='scratch'
  when unset, before the board resolution could fire

Fix (three files):
1. kanban.py: --workspace default changed from 'scratch' to None;
   _parse_workspace_flag returns (None, None) for unset values
2. kanban_db.py: create_task resolves workspace_kind from the
   board's default_workdir when workspace_kind=None, using the same
   logic as the dashboard's _default_workspace_kind: git toplevel →
   worktree, plain dir → dir, no default_workdir → scratch
3. kanban_tools.py: removed the unconditional 'scratch' fallback,
   letting workspace_kind=None flow through to create_task for board
   resolution; fixed str(None) footgun in create_task call

Explicit --workspace scratch preserves current behavior.
…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 comp/cron Cron scheduler and job management platform/telegram Telegram bot adapter needs-decision Awaiting maintainer decision before any implementation sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 24, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing with credit: your fix IS the one that shipped — #70919 preserved your authorship on the core commit and merged via #70987. This PR's copy bundled unrelated kanban changes on a stale base, so the cleaner packaging won. Thanks for finding the wedge.

@teknium1 teknium1 closed this Jul 24, 2026
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Merged via #71177 — your commit was cherry-picked with authorship preserved (rebase-merge). Fixes applied on top: _ensure_reconnect_watcher_running now uses _spawn_supervised (preserving crash-restart supervision), faulthandler path uses _hermes_home (respecting profile overrides), file handle stored for clean shutdown, and _connect_adapter_with_timeout uses task.result() instead of bool(result). The detach-on-timeout concern from your PR was also merged separately via #71176 (crediting @VaitaR's #70345). Thanks for the thorough issue report and fix!

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

Labels

comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery needs-decision Awaiting maintainer decision before any implementation P1 High — major feature broken, no workaround platform/telegram Telegram bot adapter 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