mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-01-30 06:22:04 +00:00
fix: memory leak in SSE session reset (#542)
When SSE sessions are recreated every 5 minutes, the old session's MCP server was not being closed, causing: - SimpleCache cleanup timer continuing to run indefinitely - Database connections remaining open - Cached data (~50-100MB per session) persisting in memory Added server.close() call before transport.close() in resetSessionSSE(), mirroring the existing cleanup pattern in removeSession(). Fixes #542 Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.33.4] - 2026-01-21
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Memory leak in SSE session reset** (Issue #542): Fixed memory leak when SSE sessions are recreated every 5 minutes
|
||||||
|
- Root cause: `resetSessionSSE()` only closed the transport but not the MCP server
|
||||||
|
- This left the SimpleCache cleanup timer (60-second interval) running indefinitely
|
||||||
|
- Database connections and cached data (~50-100MB per session) persisted in memory
|
||||||
|
- Fix: Added `server.close()` call before `transport.close()`, mirroring the existing cleanup pattern in `removeSession()`
|
||||||
|
- Impact: Prevents ~288 leaked server instances per day in long-running HTTP deployments
|
||||||
|
|
||||||
## [2.33.3] - 2026-01-21
|
## [2.33.3] - 2026-01-21
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.33.3",
|
"version": "2.33.4",
|
||||||
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
@@ -677,11 +677,25 @@ export class SingleSessionHTTPServer {
|
|||||||
private async resetSessionSSE(res: express.Response): Promise<void> {
|
private async resetSessionSSE(res: express.Response): Promise<void> {
|
||||||
// Clean up old session if exists
|
// Clean up old session if exists
|
||||||
if (this.session) {
|
if (this.session) {
|
||||||
|
const sessionId = this.session.sessionId;
|
||||||
|
logger.info('Closing previous session for SSE', { sessionId });
|
||||||
|
|
||||||
|
// Close server first to free resources (database, cache timer, etc.)
|
||||||
|
// This mirrors the cleanup pattern in removeSession() (issue #542)
|
||||||
|
// Handle server close errors separately so transport close still runs
|
||||||
|
if (this.session.server && typeof this.session.server.close === 'function') {
|
||||||
|
try {
|
||||||
|
await this.session.server.close();
|
||||||
|
} catch (serverError) {
|
||||||
|
logger.warn('Error closing server for SSE session', { sessionId, error: serverError });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close transport last - always attempt even if server.close() failed
|
||||||
try {
|
try {
|
||||||
logger.info('Closing previous session for SSE', { sessionId: this.session.sessionId });
|
|
||||||
await this.session.transport.close();
|
await this.session.transport.close();
|
||||||
} catch (error) {
|
} catch (transportError) {
|
||||||
logger.warn('Error closing previous session:', error);
|
logger.warn('Error closing transport for SSE session', { sessionId, error: transportError });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user