feat(socket): add configurable maxListeners to prevent memory leaks

Based on RSocket's battle-tested configuration:

- Add maxWebSocketListeners config option (default: 20)
  - 8 base WS events + 10 dynamic listeners + 2 buffer slots
- Add maxSocketClientListeners config option (default: 50)
- Replace dangerous setMaxListeners(0) with configurable limits
- Add warning log if user explicitly sets limit to 0

BREAKING: Previous behavior used setMaxListeners(0) which removed
all limits. Now defaults to safe limits but can be overridden via config.
This commit is contained in:
Claude
2026-01-20 05:19:22 +00:00
parent 4f623b4942
commit 3afb8b80c5
4 changed files with 34 additions and 3 deletions
+7 -1
View File
@@ -13,7 +13,13 @@ export abstract class AbstractSocketClient extends EventEmitter {
public config: SocketConfig
) {
super()
this.setMaxListeners(0)
// Set max listeners from config (default: 50)
// WARNING: 0 disables limit and allows potential memory leaks
const maxListeners = this.config.maxSocketClientListeners ?? 50
if (maxListeners === 0) {
this.config.logger?.warn('SocketClient setMaxListeners(0) allows UNLIMITED listeners - potential memory leak!')
}
this.setMaxListeners(maxListeners)
}
abstract connect(): void
+7 -1
View File
@@ -31,7 +31,13 @@ export class WebSocketClient extends AbstractSocketClient {
agent: this.config.agent
})
this.socket.setMaxListeners(0)
// Set max listeners from config (default: 20)
// WARNING: 0 disables limit and allows potential memory leaks
const maxListeners = this.config.maxWebSocketListeners ?? 20
if (maxListeners === 0) {
this.config.logger?.warn('WebSocket setMaxListeners(0) allows UNLIMITED listeners - potential memory leak!')
}
this.socket.setMaxListeners(maxListeners)
const events = ['close', 'error', 'upgrade', 'message', 'open', 'ping', 'pong', 'unexpected-response']