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:
@@ -80,7 +80,11 @@ export const DEFAULT_CONNECTION_CONFIG: SocketConfig = {
|
||||
cachedGroupMetadata: async () => undefined,
|
||||
makeSignalRepository: makeLibSignalRepository,
|
||||
// Circuit breaker configuration
|
||||
enableCircuitBreaker: true
|
||||
enableCircuitBreaker: true,
|
||||
// Listener limits (memory leak prevention)
|
||||
// 8 base WS events + 10 dynamic listeners + 2 buffer slots
|
||||
maxWebSocketListeners: 20,
|
||||
maxSocketClientListeners: 50
|
||||
}
|
||||
|
||||
export const MEDIA_PATH_MAP: { [T in MediaType]?: string } = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
@@ -165,4 +165,19 @@ export type SocketConfig = {
|
||||
|
||||
/** Circuit breaker configuration for message operations */
|
||||
messageCircuitBreaker?: Partial<CircuitBreakerOptions>
|
||||
|
||||
// === Listener Limits (Memory Leak Prevention) ===
|
||||
|
||||
/**
|
||||
* Max WebSocket event listeners (default: 20)
|
||||
* Calculated as: 8 base WS events + 10 dynamic listeners + 2 buffer slots
|
||||
* WARNING: Setting to 0 disables limit and allows potential memory leaks!
|
||||
*/
|
||||
maxWebSocketListeners?: number
|
||||
|
||||
/**
|
||||
* Max SocketClient event listeners (default: 50)
|
||||
* WARNING: Setting to 0 disables limit and allows potential memory leaks!
|
||||
*/
|
||||
maxSocketClientListeners?: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user