fix(ws): drop dead connections, bound message floods and pending sketch input - #167
Merged
Merged
Conversation
…ch input A half-open WebSocket kept its runner and admission until the simulation timeout, and inbound messages were unbounded. The server now pings every 30 s and terminates connections that miss a pong, drops messages beyond a per-connection token bucket, and stops buffering stdin past 1 MiB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
R4b of the refactoring series (
docs/UNOSIM_REFACTORING_OPL.md), audit finding A7 (WebSocket part).Findings re-verified
SIMULATION_ALREADY_ACTIVEmeanwhile.start_simulationwas rate-limited; eachserial_input/set_pin_valuebecame a stdin write. If the sketch never reads Serial, Node buffered every write without bound.stop_simulation/code_changedcan abort a start still waiting for a runner (abortQueuedAcquire). Double starts are blocked by the reservation, and the synchronous handlers keep their order. Serializing would break stop-while-queued, so it is not changed. Recorded asFALSIFIED.Change
WS_HEARTBEAT_INTERVAL_MS(default 30 s). A connection that has not answered the previous ping is terminated. The existing close handler releases runner and reservation. Browsers answer pings automatically; the interval isunref'd and cleared onwss.close.ProcessController.writeStdinrefuses input once 1 MiB is pending in the child's stdin.Tests
tests/server/routes/simulation-connection-lifecycle.test.ts:autoPong: falseis terminated and its simulation freed (runner stopped and released, admission 0);tests/server/services/process-controller-stdin-bound.test.ts(child that never reads stdin: writes are refused; the pending backlog stays bounded).npm run check, ESLint, unit 2721 passed, Docker integration 27/27 locally, pre-push incl. Sonar quality gate PASSED.🤖 Generated with Claude Code