mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +00:00
The salvaged fix (#58272) guarded the primary network-error reconnect path. Issue #58270's Scope section names three more unguarded await updater.stop() sites that can hang identically on a CLOSE-WAIT socket: - conflict handler (before the retry back-off sleep) - conflict-retries-exhausted teardown (before the fatal notify) - disconnect() teardown (would hang gateway shutdown/restart) Each is now wrapped in asyncio.wait_for(..., _UPDATER_STOP_TIMEOUT) with a warning on timeout, matching the primary path, so no reconnect/teardown ladder can wedge on a dead socket. Also hoist the shared 15.0s bound to a single module constant _UPDATER_STOP_TIMEOUT (self-documenting + DRY across all 4 sites), and update the CLOSE-WAIT regression test to patch that constant instead of monkeypatching asyncio.wait_for process-wide. Fatal-notify idempotency: bounding the conflict-exhausted teardown stop() adds an await AFTER _set_fatal_error, which yields the loop and lets a concurrent retry task (scheduled by an earlier conflict, already suspended past the entry guard) reach the fatal branch too — double-firing the fatal handler (surfaced as a Python 3.11 CI failure in test_polling_conflict_becomes_fatal_after_retries). Snapshot the pre-transition fatal state and only notify on the first transition. |
||
|---|---|---|
| .. | ||
| browser | ||
| context_engine | ||
| cron_providers | ||
| dashboard_auth | ||
| disk-cleanup | ||
| google_meet | ||
| hermes-achievements | ||
| image_gen | ||
| kanban | ||
| memory | ||
| model-providers | ||
| observability | ||
| platforms | ||
| security-guidance | ||
| spotify | ||
| teams_pipeline | ||
| video_gen | ||
| web | ||
| __init__.py | ||
| plugin_utils.py | ||