Skip to content

Fix engine connection lifecycle: leaks, crashes, unhandled rejections - #109

Merged
thegalah merged 1 commit into
masterfrom
fix/engine-connection-lifecycle
Jul 6, 2026
Merged

Fix engine connection lifecycle: leaks, crashes, unhandled rejections#109
thegalah merged 1 commit into
masterfrom
fix/engine-connection-lifecycle

Conversation

@thegalah

@thegalah thegalah commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Hardens the WebSocket/networking and lifecycle layer of the engine, which previously had no test coverage and several process-crash paths.

ConnectionTracker: remove connections by identity instead of a stored index. The index map went stale the moment connections.sort() ran on every add, so a disconnect removed the wrong socket (leaking the dead one, which kept receiving broadcasts). Add ConnectionTracker.test.ts covering multi-connection removal, role ordering, and interleaved churn.

Socket handlers: register an "error" listener on every socket so an abnormal reset logs instead of throwing an unhandled EventEmitter error that crashes the process. Guard Send with a readyState check + try/catch so one dead socket can't abort a broadcast to everyone else. Close rejected connections (GameWebSocket catch + attachSocketHandler now throws on unknown roles) instead of leaking open sockets.

Lifecycle: install process-level unhandledRejection/uncaughtException handlers so a stray async failure (webhook, telemetry, admin state eval) no longer tears down a live match, and attach .catch to the previously un-awaited async calls. Also add the missing return after the game-complete branch that broadcast an extra Tick after EndGameState.

Verified: tsc --noEmit clean; jest 15 suites / 46 tests passing.

Hardens the WebSocket/networking and lifecycle layer of the engine,
which previously had no test coverage and several process-crash paths.

ConnectionTracker: remove connections by identity instead of a stored
index. The index map went stale the moment connections.sort() ran on
every add, so a disconnect removed the wrong socket (leaking the dead
one, which kept receiving broadcasts). Add ConnectionTracker.test.ts
covering multi-connection removal, role ordering, and interleaved churn.

Socket handlers: register an "error" listener on every socket so an
abnormal reset logs instead of throwing an unhandled EventEmitter error
that crashes the process. Guard Send with a readyState check + try/catch
so one dead socket can't abort a broadcast to everyone else. Close
rejected connections (GameWebSocket catch + attachSocketHandler now
throws on unknown roles) instead of leaking open sockets.

Lifecycle: install process-level unhandledRejection/uncaughtException
handlers so a stray async failure (webhook, telemetry, admin state eval)
no longer tears down a live match, and attach .catch to the previously
un-awaited async calls. Also add the missing return after the
game-complete branch that broadcast an extra Tick after EndGameState.

Verified: tsc --noEmit clean; jest 15 suites / 46 tests passing.
@thegalah
thegalah merged commit 8d29cd2 into master Jul 6, 2026
1 check passed
@thegalah
thegalah deleted the fix/engine-connection-lifecycle branch July 6, 2026 02:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant