mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-08 22:33:08 +00:00
Critical bug fix for production crashes during session cleanup. **Root Cause:** Infinite recursion caused by circular event handler chain: - removeSession() called transport.close() - transport.close() triggered onclose event handler - onclose handler called removeSession() again - Loop continued until stack overflow **Solution:** Delete transport from registry BEFORE closing to break circular reference: 1. Store transport reference 2. Delete from this.transports first 3. Close transport after deletion 4. When onclose fires, transport no longer found, no recursion **Impact:** - Eliminates "RangeError: Maximum call stack size exceeded" errors - Fixes session cleanup crashes every 5 minutes in production - Prevents potential memory leaks from failed cleanup **Testing:** - Added regression test for infinite recursion prevention - All 39 session management tests pass - Build and typecheck succeed Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Closes #427
This commit is contained in:
committed by
GitHub
parent
1bbfaabbc2
commit
5575630711
@@ -155,17 +155,22 @@ export class SingleSessionHTTPServer {
|
||||
*/
|
||||
private async removeSession(sessionId: string, reason: string): Promise<void> {
|
||||
try {
|
||||
// Close transport if exists
|
||||
if (this.transports[sessionId]) {
|
||||
await this.transports[sessionId].close();
|
||||
delete this.transports[sessionId];
|
||||
}
|
||||
|
||||
// Remove server, metadata, and context
|
||||
// Store reference to transport before deletion
|
||||
const transport = this.transports[sessionId];
|
||||
|
||||
// Delete transport FIRST to prevent onclose handler from triggering recursion
|
||||
// This breaks the circular reference: removeSession -> close -> onclose -> removeSession
|
||||
delete this.transports[sessionId];
|
||||
delete this.servers[sessionId];
|
||||
delete this.sessionMetadata[sessionId];
|
||||
delete this.sessionContexts[sessionId];
|
||||
|
||||
|
||||
// Close transport AFTER deletion
|
||||
// When onclose handler fires, it won't find the transport anymore
|
||||
if (transport) {
|
||||
await transport.close();
|
||||
}
|
||||
|
||||
logger.info('Session removed', { sessionId, reason });
|
||||
} catch (error) {
|
||||
logger.warn('Error removing session', { sessionId, reason, error });
|
||||
|
||||
Reference in New Issue
Block a user