mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 13:33:11 +00:00
fix: critical memory leak from per-session database connections (#554)
* fix: critical memory leak from per-session database connections (#542) Each MCP session was creating its own database connection (~900MB), causing OOM kills every ~20 minutes with 3-4 concurrent sessions. Changes: - Add SharedDatabase singleton pattern - all sessions share ONE connection - Reduce session timeout from 30 min to 5 min (configurable) - Add eager cleanup for reconnecting instances - Fix telemetry event listener leak Memory impact: ~900MB/session → ~68MB shared + ~5MB/session overhead Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en * fix: resolve test failures from shared database race conditions - Fix `shutdown()` to respect shared database pattern (was directly closing) - Add `await this.initialized` in both `close()` and `shutdown()` to prevent race condition where cleanup runs while initialization is in progress - Add double-shutdown protection with `isShutdown` flag - Export `SharedDatabaseState` type for proper typing - Include error details in debug logs - Add MCP server close to `shutdown()` for consistency with `close()` - Null out `earlyLogger` in `shutdown()` for consistency The CI test failure "The database connection is not open" was caused by: 1. `shutdown()` directly calling `this.db.close()` which closed the SHARED database connection, breaking subsequent tests 2. Race condition where `shutdown()` ran before initialization completed Conceived by Romuald Członkowski - www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: add unit tests for shared-database module Add comprehensive unit tests covering: - getSharedDatabase: initialization, reuse, different path error, concurrent requests - releaseSharedDatabase: refCount decrement, double-release guard - closeSharedDatabase: state clearing, error handling, re-initialization - Helper functions: isSharedDatabaseInitialized, getSharedDatabaseRefCount 21 tests covering the singleton database connection pattern used to prevent ~900MB memory leaks per session. Conceived by Romuald Członkowski - www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
fad3437977
commit
c8c76e435d
36
CHANGELOG.md
36
CHANGELOG.md
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.33.5] - 2026-01-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Critical memory leak: per-session database connections** (Issue #542): Fixed severe memory leak where each MCP session created its own database connection (~900MB per session)
|
||||
- Root cause: `N8NDocumentationMCPServer` called `createDatabaseAdapter()` for every new session, duplicating the entire 68MB database in memory
|
||||
- With 3-4 sessions, memory would exceed 4GB causing OOM kills every ~20 minutes
|
||||
- Fix: Implemented singleton `SharedDatabase` pattern - all sessions now share ONE database connection
|
||||
- Memory impact: Reduced from ~900MB per session to ~68MB total (shared) + ~5MB per session overhead
|
||||
- Added `getSharedDatabase()` and `releaseSharedDatabase()` for thread-safe connection management
|
||||
- Added reference counting to track active sessions using the shared connection
|
||||
|
||||
- **Session timeout optimization**: Reduced default session timeout from 30 minutes to 5 minutes
|
||||
- Faster cleanup of stale sessions reduces memory buildup
|
||||
- Configurable via `SESSION_TIMEOUT_MINUTES` environment variable
|
||||
|
||||
- **Eager instance cleanup**: When a client reconnects, previous sessions for the same instanceId are now immediately cleaned up
|
||||
- Prevents memory accumulation from reconnecting clients in multi-tenant deployments
|
||||
|
||||
- **Telemetry event listener leak**: Fixed event listeners in `TelemetryBatchProcessor` that were never removed
|
||||
- Added proper cleanup in `stop()` method
|
||||
- Added guard against multiple `start()` calls
|
||||
|
||||
### Added
|
||||
|
||||
- **New module: `src/database/shared-database.ts`** - Singleton database manager
|
||||
- `getSharedDatabase(dbPath)`: Thread-safe initialization with promise lock pattern
|
||||
- `releaseSharedDatabase(state)`: Reference counting for cleanup
|
||||
- `closeSharedDatabase()`: Graceful shutdown for process termination
|
||||
- `isSharedDatabaseInitialized()` and `getSharedDatabaseRefCount()`: Monitoring helpers
|
||||
|
||||
### Changed
|
||||
|
||||
- **`N8NDocumentationMCPServer.close()`**: Now releases shared database reference instead of closing the connection
|
||||
- **`SingleSessionHTTPServer.shutdown()`**: Calls `closeSharedDatabase()` during graceful shutdown
|
||||
|
||||
## [2.33.4] - 2026-01-21
|
||||
|
||||
### Fixed
|
||||
|
||||
Reference in New Issue
Block a user