The live event streams queue frames without checking backpressure (api/events/servers/+server.ts:20-29), so a stalled client buffers status updates in memory until its connection drops.
Fix
Check the stream's desired size / backpressure before enqueuing, and drop or coalesce frames (or close the connection) for clients that fall behind.
The live event streams queue frames without checking backpressure (`api/events/servers/+server.ts:20-29`), so a stalled client buffers status updates in memory until its connection drops.
**Fix**
- Check the stream's desired size / backpressure before enqueuing, and drop or coalesce frames (or close the connection) for clients that fall behind.
Reviewed deb2d21f29. The fix is done, so I'm closing this.
Checklist
Backpressure checked before enqueuing. Both live streams now use one helper, eventStreamResponse (event-stream.ts). It caps each connection's queue at 64 frames (event-stream.ts:8,51), and checks desiredSize before every enqueue. A client that falls behind is closed instead of buffered (event-stream.ts:32-36), and the helper releases its subscription and heartbeat itself, since close() doesn't call cancel().
Review notes
This only works if the server stops reading for a stalled socket. It does: SvelteKit's Node writer waits for drain when res.write returns false (@sveltejs/kit/src/exports/node/index.js:222-225), so the queue really fills.
Both clients use EventSource and only close it when the page tears down (servers.ts:141, pipeline.ts:60). A closed stream therefore reconnects automatically, and the servers stream sends a fresh snapshot on connect.
Good extra: the new tests cover a stalled client not affecting a reading one, and heartbeats alone filling the queue.
The 5 affected test files pass locally (105 tests), the full suite passes (208 files, 2,625 tests), and npm run check reports 0 errors.
Reviewed deb2d21f29ed1f0f4721d09a704b5f84fff64272. The fix is done, so I'm closing this.
**Checklist**
- [x] **Backpressure checked before enqueuing.** Both live streams now use one helper, `eventStreamResponse` (`event-stream.ts`). It caps each connection's queue at 64 frames (`event-stream.ts:8,51`), and checks `desiredSize` before every enqueue. A client that falls behind is closed instead of buffered (`event-stream.ts:32-36`), and the helper releases its subscription and heartbeat itself, since `close()` doesn't call `cancel()`.
**Review notes**
- This only works if the server stops reading for a stalled socket. It does: SvelteKit's Node writer waits for `drain` when `res.write` returns false (`@sveltejs/kit/src/exports/node/index.js:222-225`), so the queue really fills.
- Both clients use `EventSource` and only close it when the page tears down (`servers.ts:141`, `pipeline.ts:60`). A closed stream therefore reconnects automatically, and the servers stream sends a fresh snapshot on connect.
- Good extra: the new tests cover a stalled client not affecting a reading one, and heartbeats alone filling the queue.
- The 5 affected test files pass locally (105 tests), the full suite passes (208 files, 2,625 tests), and `npm run check` reports 0 errors.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The live event streams queue frames without checking backpressure (
api/events/servers/+server.ts:20-29), so a stalled client buffers status updates in memory until its connection drops.Fix
Reviewed
deb2d21f29. The fix is done, so I'm closing this.Checklist
eventStreamResponse(event-stream.ts). It caps each connection's queue at 64 frames (event-stream.ts:8,51), and checksdesiredSizebefore every enqueue. A client that falls behind is closed instead of buffered (event-stream.ts:32-36), and the helper releases its subscription and heartbeat itself, sinceclose()doesn't callcancel().Review notes
drainwhenres.writereturns false (@sveltejs/kit/src/exports/node/index.js:222-225), so the queue really fills.EventSourceand only close it when the page tears down (servers.ts:141,pipeline.ts:60). A closed stream therefore reconnects automatically, and the servers stream sends a fresh snapshot on connect.npm run checkreports 0 errors.