fix(tui_gateway): suppress WS peer-hangup teardown error flood (#50005) (#54126)

When the Desktop forcibly closes its WebSocket mid-write, asyncio logs a
full traceback for every pending connection-lost callback — 50+ identical
WinError 10054 (ConnectionResetError) lines per disconnect on Windows, the
equivalent ConnectionResetError/BrokenPipeError on POSIX. These are not
actionable: they are the expected side effect of the peer hanging up before
our writes drained.

Install a loop exception handler on the gateway serving loop that collapses
exactly this teardown class (ConnectionResetError/ConnectionAbortedError/
BrokenPipeError originating from _call_connection_lost) to a single debug
line, forwarding every other loop error to the existing/default handler
unchanged so genuine loop bugs still surface. Idempotent per loop.
This commit is contained in:
Teknium 2026-06-28 02:35:01 -07:00 committed by GitHub
parent 6eec0d4f08
commit fde1c8570f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 210 additions and 0 deletions

View file

@ -13686,6 +13686,19 @@ def start_server(
print(f" Hermes Web UI → http://{host}:{actual_port}")
_maybe_open_browser(host, actual_port, open_browser, initial_profile)
# Collapse the peer-hangup teardown flood (#50005). When the Desktop
# forcibly closes its WebSocket mid-write, asyncio logs a full
# traceback per pending connection-lost callback — 50+ identical
# WinError 10054 (ConnectionResetError) lines per disconnect on
# Windows. This filter downgrades exactly that class to one debug
# line and passes every other loop error through unchanged.
try:
from tui_gateway.loop_noise import install_loop_noise_filter
install_loop_noise_filter(asyncio.get_running_loop())
except Exception as exc: # pragma: no cover - best-effort
_log.debug("loop noise filter install skipped: %s", exc)
await server.main_loop()
if server.started:
await server.shutdown()