fix(ws_highway): swallow a mid-stream WebSocketDisconnect quietly (#845)

* fix(ws_highway): swallow a mid-stream WebSocketDisconnect quietly

Pre-existing (byte-identical to origin/main), flagged by CodeRabbit on #844: the
outer try's only guard was `except Exception as e: log.exception("highway_ws
unhandled error")`. The inner `except WebSocketDisconnect` covers ONLY the
post-`ready` keep-alive loop, and the drum_tab/notation sends have their own
localized guards — but the ~13 other streamed sends (beats, sections, notes,
chords, anchors, …) fall through to the blanket handler. Since
WebSocketDisconnect is an Exception subclass, a routine tab-close mid-load was
logged as an error at whichever send was in flight.

Fix: a dedicated `except WebSocketDisconnect: return` before the blanket handler,
matching the two localized guards and the lib/ coding guideline.

tests/test_ws_highway_disconnect.py drives highway_ws with a fake websocket that
raises WebSocketDisconnect on the first streamed send (`loading`), over a real
minimal sloppak. Negative-checked: removing the guard makes it fail (the
disconnect is logged as `highway_ws unhandled error`); the fix passes. Uses a
raw handler on `feedBack.server` rather than caplog, since configure_logging()
reroutes that logger through structlog where caplog doesn't observe it.

Full suite green. Closes the review thread on #844.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(ws_highway): assert streaming stops after disconnect (exactly one send) — CodeRabbit

The stub now raises only on the first send and the test asserts ws.sends == 1,
so a handler that caught the disconnect and kept streaming would fail. Still
negative-checked: removing the guard fails the test.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Byron Gamatos
2026-07-10 21:30:53 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 514461167e
commit c8701991cb
2 changed files with 117 additions and 0 deletions
+7
View File
@@ -1036,6 +1036,13 @@ async def highway_ws(websocket: WebSocket, filename: str, arrangement: int = -1,
except WebSocketDisconnect:
pass
except WebSocketDisconnect:
# A client that navigates away / closes the tab mid-stream is routine,
# not an error. Without this, the disconnect falls through to the blanket
# handler below and logs `highway_ws unhandled error` for every send point
# (the inner guard only covers the post-`ready` keep-alive loop). Matches
# the two localized WebSocketDisconnect guards in the streaming body.
return
except Exception as e:
log.exception("highway_ws unhandled error for %s", filename)
try: