Cleanup orphaned Electron child processes

Add cleanupOrphanedProcesses to terminate leftover child processes when running in Electron. The function imports Electron at runtime, uses app.getAppMetrics() to enumerate processes, excludes the main and provided worker PIDs, and sends SIGTERM to stray PIDs while ignoring already-dead processes and API errors. Also invoke this cleanup in restartWorker after starting the new worker to avoid lingering processes after restarts. Includes @ts-ignore for the dynamic Electron import and debug logging on failure.
This commit is contained in:
手瓜一十雪
2026-02-13 15:45:05 +08:00
parent 35af50bb73
commit f17abccfdc
2 changed files with 44 additions and 1 deletions

View File

@@ -10,7 +10,7 @@ permissions: write-all
env:
OPENROUTER_API_URL: https://91vip.futureppo.top/v1/chat/completions
OPENROUTER_MODEL: "gemini-3-flash-preview"
OPENROUTER_MODEL: "glm-4.7"
RELEASE_NAME: "NapCat"
jobs:

View File

@@ -113,6 +113,42 @@ function forceKillProcess (pid: number): void {
}
}
/**
* 清理进程树中的残留子进程Electron 模式专用)
* 排除当前主进程和新 worker 进程
*/
async function cleanupOrphanedProcesses (excludePids: number[]): Promise<void> {
if (!isElectron) return;
try {
// 使用 Electron 的 app.getAppMetrics() 获取所有相关进程
// @ts-ignore - electron 运行时存在但类型声明可能缺失
const electron = await import('electron');
if (electron.app && typeof electron.app.getAppMetrics === 'function') {
const metrics = electron.app.getAppMetrics();
const mainPid = process.pid;
for (const metric of metrics) {
const pid = metric.pid;
// 排除主进程、新 worker 进程和明确排除的 PID
if (pid === mainPid || excludePids.includes(pid)) {
continue;
}
// 尝试终止残留进程
try {
process.kill(pid, 'SIGTERM');
logger.log(`[NapCat] [Process] 已清理残留进程: PID ${pid} (${metric.type})`);
} catch {
// 进程可能已经不存在,忽略错误
}
}
}
} catch (error) {
// Electron API 不可用或出错,静默忽略
logger.logDebug?.('[NapCat] [Process] 清理残留进程时出错:', error);
}
}
/**
* 重启 Worker 进程
*/
@@ -166,6 +202,13 @@ export async function restartWorker (secretKey?: string, port?: number): Promise
// 5. 启动新进程(重启模式不传递快速登录参数,传递密钥和端口)
await startWorker(false, secretKey, port);
// 6. Electron 模式下清理可能残留的子进程
if (isElectron && currentWorker?.pid) {
const excludePids = [process.pid, currentWorker.pid];
await cleanupOrphanedProcesses(excludePids);
}
isRestarting = false;
}