chore: bump version to 10.0.4
Reverts v10.0.3 chroma-mcp spawn storm fix (broken release). Restores codebase to v10.0.2 state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
import http from 'http';
|
||||
import { execFileSync } from 'child_process';
|
||||
import { logger } from '../../utils/logger.js';
|
||||
import {
|
||||
getChildProcesses,
|
||||
@@ -77,21 +76,6 @@ export async function performGracefulShutdown(config: GracefulShutdownConfig): P
|
||||
await config.dbManager.close();
|
||||
}
|
||||
|
||||
// STEP 5.5: Kill any chroma-mcp children that survived transport.close() (Unix only)
|
||||
// On Unix, getChildProcesses() returns [] (Windows-only), so chroma-mcp
|
||||
// subprocesses spawned via StdioClientTransport may escape STEP 5 cleanup
|
||||
if (process.platform !== 'win32') {
|
||||
try {
|
||||
execFileSync('pkill', ['-P', String(process.pid), '-f', 'chroma-mcp'], {
|
||||
timeout: 3000,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
logger.info('SYSTEM', 'Killed chroma-mcp child processes');
|
||||
} catch {
|
||||
// pkill returns exit code 1 if no processes matched — that's fine
|
||||
}
|
||||
}
|
||||
|
||||
// STEP 6: Force kill any remaining child processes (Windows zombie port fix)
|
||||
if (childPids.length > 0) {
|
||||
logger.info('SYSTEM', 'Force killing remaining children');
|
||||
|
||||
@@ -339,77 +339,6 @@ export async function cleanupOrphanedProcesses(): Promise<void> {
|
||||
logger.info('SYSTEM', 'Orphaned processes cleaned up', { count: pidsToKill.length });
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up excess chroma-mcp processes by count (not age).
|
||||
*
|
||||
* Unlike cleanupOrphanedProcesses() which uses ORPHAN_MAX_AGE_MINUTES = 30,
|
||||
* this function kills by count — essential for catching spawn storms where
|
||||
* all processes are young. Keeps the newest processes (by elapsed time)
|
||||
* and kills the rest.
|
||||
*
|
||||
* Returns the number of processes killed.
|
||||
*/
|
||||
export async function cleanupExcessChromaProcesses(maxAllowed: number = 2): Promise<number> {
|
||||
// Windows: Chroma is disabled entirely, no cleanup needed
|
||||
if (process.platform === 'win32') return 0;
|
||||
|
||||
try {
|
||||
const { stdout } = await execAsync(
|
||||
'ps -eo pid,etime,command | grep -E "chroma-mcp" | grep -v grep || true'
|
||||
);
|
||||
|
||||
if (!stdout.trim()) return 0;
|
||||
|
||||
const processes: Array<{ pid: number; ageMinutes: number }> = [];
|
||||
|
||||
for (const line of stdout.trim().split('\n')) {
|
||||
if (!line.trim()) continue;
|
||||
const match = line.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);
|
||||
if (!match) continue;
|
||||
|
||||
const pid = parseInt(match[1], 10);
|
||||
const etime = match[2];
|
||||
|
||||
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) continue;
|
||||
|
||||
const ageMinutes = parseElapsedTime(etime);
|
||||
// Skip entries with unparseable etime (-1) to avoid sort corruption
|
||||
if (ageMinutes < 0) continue;
|
||||
processes.push({ pid, ageMinutes });
|
||||
}
|
||||
|
||||
if (processes.length <= maxAllowed) return 0;
|
||||
|
||||
// Sort: newest first (lowest age), keep maxAllowed, kill rest
|
||||
processes.sort((a, b) => a.ageMinutes - b.ageMinutes);
|
||||
const toKill = processes.slice(maxAllowed);
|
||||
|
||||
let killed = 0;
|
||||
for (const { pid } of toKill) {
|
||||
try {
|
||||
process.kill(pid, 'SIGTERM');
|
||||
killed++;
|
||||
logger.info('SYSTEM', 'Killed excess chroma-mcp process', { pid });
|
||||
} catch {
|
||||
// Process may already be dead
|
||||
}
|
||||
}
|
||||
|
||||
if (killed > 0) {
|
||||
logger.warn('SYSTEM', 'Cleaned up excess chroma-mcp processes by count', {
|
||||
found: processes.length,
|
||||
killed,
|
||||
maxAllowed
|
||||
});
|
||||
}
|
||||
|
||||
return killed;
|
||||
} catch (error) {
|
||||
logger.debug('SYSTEM', 'Failed to enumerate chroma-mcp processes', {}, error as Error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a detached daemon process
|
||||
* Returns the child PID or undefined if spawn failed
|
||||
|
||||
Reference in New Issue
Block a user