feat: auto-cleanup orphaned chroma-mcp processes on worker startup
Enhancement to process leak fix from v7.1.9 - automatically detects and
kills orphaned chroma-mcp processes when the worker starts.
Changes:
- Added cleanupOrphanedProcesses() method to WorkerService
- Scans for existing chroma-mcp processes on startup
- Kills all found processes before creating new ones
- Logs cleanup activity (process count and PIDs)
- Non-fatal error handling (continues on cleanup failure)
Benefits:
- Automatically recovers from pre-7.1.9 process leaks
- Ensures clean slate on every worker restart
- No manual intervention needed to cleanup orphans
- Prevents accumulation even if v7.1.9 close() fails
Verified working in logs:
[INFO] [SYSTEM] Cleaning up orphaned chroma-mcp processes {count=2, pids=33753,33750}
[INFO] [SYSTEM] Orphaned processes cleaned up {count=2}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -13,6 +13,10 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|||||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
||||||
import { getWorkerPort, getWorkerHost } from '../shared/worker-utils.js';
|
import { getWorkerPort, getWorkerHost } from '../shared/worker-utils.js';
|
||||||
import { logger } from '../utils/logger.js';
|
import { logger } from '../utils/logger.js';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
|
||||||
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
// Import composed domain services
|
// Import composed domain services
|
||||||
import { DatabaseManager } from './worker/DatabaseManager.js';
|
import { DatabaseManager } from './worker/DatabaseManager.js';
|
||||||
@@ -149,6 +153,52 @@ export class WorkerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up orphaned chroma-mcp processes from previous worker sessions
|
||||||
|
* Prevents process accumulation and memory leaks
|
||||||
|
*/
|
||||||
|
private async cleanupOrphanedProcesses(): Promise<void> {
|
||||||
|
try {
|
||||||
|
// Find all chroma-mcp processes
|
||||||
|
const { stdout } = await execAsync('ps aux | grep "chroma-mcp" | grep -v grep || true');
|
||||||
|
|
||||||
|
if (!stdout.trim()) {
|
||||||
|
logger.debug('SYSTEM', 'No orphaned chroma-mcp processes found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = stdout.trim().split('\n');
|
||||||
|
const pids: number[] = [];
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const parts = line.trim().split(/\s+/);
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const pid = parseInt(parts[1], 10);
|
||||||
|
if (!isNaN(pid)) {
|
||||||
|
pids.push(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pids.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('SYSTEM', 'Cleaning up orphaned chroma-mcp processes', {
|
||||||
|
count: pids.length,
|
||||||
|
pids
|
||||||
|
});
|
||||||
|
|
||||||
|
// Kill all found processes
|
||||||
|
await execAsync(`kill ${pids.join(' ')}`);
|
||||||
|
|
||||||
|
logger.info('SYSTEM', 'Orphaned processes cleaned up', { count: pids.length });
|
||||||
|
} catch (error) {
|
||||||
|
// Non-fatal - log and continue
|
||||||
|
logger.warn('SYSTEM', 'Failed to cleanup orphaned processes', {}, error as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the worker service
|
* Start the worker service
|
||||||
*/
|
*/
|
||||||
@@ -173,6 +223,9 @@ export class WorkerService {
|
|||||||
* Background initialization - runs after HTTP server is listening
|
* Background initialization - runs after HTTP server is listening
|
||||||
*/
|
*/
|
||||||
private async initializeBackground(): Promise<void> {
|
private async initializeBackground(): Promise<void> {
|
||||||
|
// Clean up any orphaned chroma-mcp processes BEFORE starting our own
|
||||||
|
await this.cleanupOrphanedProcesses();
|
||||||
|
|
||||||
// Initialize database (once, stays open)
|
// Initialize database (once, stays open)
|
||||||
await this.dbManager.initialize();
|
await this.dbManager.initialize();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user