Telegram (ask questions / claim the issue here first): https://t.me/+DOylgFv1jyJlNzM0
Why this matters
sse.service.ts:216 (broadcast) and :92 (sendHeartbeat) call client.res.write(...) and discard the boolean return value. When a consumer cannot drain (slow/stalled socket), Node buffers every event in the socket's writable buffer with no high-water-mark check, no drain wait, and no max-buffer disconnect. Under the documented 10k-connection / 1k-events-sec target a few stalled clients cause unbounded heap growth and OOM. broadcast also has an empty catch that does not prune the failed client (unlike sendHeartbeat).
Acceptance criteria
Files to touch
backend/src/services/sse.service.ts
Out of scope
- Switching transport from SSE to WebSocket
Why this matters
sse.service.ts:216 (broadcast) and :92 (sendHeartbeat) call client.res.write(...) and discard the boolean return value. When a consumer cannot drain (slow/stalled socket), Node buffers every event in the socket's writable buffer with no high-water-mark check, no drain wait, and no max-buffer disconnect. Under the documented 10k-connection / 1k-events-sec target a few stalled clients cause unbounded heap growth and OOM. broadcast also has an empty catch that does not prune the failed client (unlike sendHeartbeat).
Acceptance criteria
Files to touch
backend/src/services/sse.service.tsOut of scope