Skip to content

feat: backpressure-aware async broadcast with per-client drain queues - #217

Open
ayomidemariam wants to merge 2 commits into
RiftCore00:mainfrom
ayomidemariam:feature/broadcast-backpressure
Open

feat: backpressure-aware async broadcast with per-client drain queues#217
ayomidemariam wants to merge 2 commits into
RiftCore00:mainfrom
ayomidemariam:feature/broadcast-backpressure

Conversation

@ayomidemariam

@ayomidemariam ayomidemariam commented Jul 27, 2026

Copy link
Copy Markdown

Summary

This PR implements backpressure-aware async broadcasting with per-client drain queues to prevent event loop starvation in large rooms.

Changes

  • Constructor options: RoomManager now accepts optional backpressure configuration with enabled, highWaterMark, slowConsumerTimeout, and batchSize options
  • Batched broadcasting: When backpressure is enabled, broadcasts process sends in configurable batches using setImmediate to yield control back to the event loop
  • Slow consumer detection: Clients whose ws.bufferedAmount exceeds highWaterMark (default 1MB) are flagged as slow
  • Message coalescing: Slow consumers receive only the latest location_update message, dropping intermediate updates
  • Auto-eviction: Slow consumers that don't drain within slowConsumerTimeout (default 30s) are terminated via ws.close(4000, "Slow consumer")
  • Observability: New getRoomStats(roomId) method returns member count, per-client send queue depths, and slow consumer list
  • Clean disconnect: Slow consumer tracking state is properly cleaned up on disconnect to prevent memory leaks

Backward Compatibility

The backpressure behavior is opt-in. When no options are provided (or enabled: false), broadcast() behaves identically to the current synchronous implementation. All 30 existing room-manager tests pass unchanged.

Testing

  • All existing tests pass (163 passed, 15 skipped)
  • Lint passes cleanly
  • No new dependencies added
  • No existing test files modified

Closes #194

- Import createRateLimiter from ./rate-limiter.js
- Add safeSend helper for outbound messages
- Implement per-message rate limiting before validation
- Clean up rate limiter state on disconnect
- Remove ipConnectionCount and server from return value
- All 18 test suites pass (163 tests)
…ain queues

- Add backpressure options to RoomManager constructor (opt-in)
- Batch broadcasts using setImmediate to prevent event loop starvation
- Detect slow consumers via ws.bufferedAmount high water mark
- Coalesce location_update messages for slow consumers
- Auto-terminate slow consumers after configurable timeout
- Add getRoomStats() for observability (queue depths, slow consumers)
- Clean up slow consumer state on disconnect (no memory leaks)
- All existing tests pass unchanged (backward compatible)

Closes #734
Closes #733
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