修复了引擎运行时读取log的多余的tail进程

This commit is contained in:
jinchao 2025-05-14 16:11:32 +08:00
parent cc042dc497
commit 2b39135c63
3 changed files with 61 additions and 39 deletions

Binary file not shown.

View File

@ -635,6 +635,15 @@ class RunSimulation extends HTMLElement {
// 关闭SSE连接 // 关闭SSE连接
closeEventSource() { closeEventSource() {
if (this.eventSource) { if (this.eventSource) {
// 通知后端清理tail进程
if (this.currentSimulationId) {
fetch(`/api/cleanup-simulation/${this.currentSimulationId}`, {
method: 'POST'
}).catch(error => {
console.error('清理仿真资源失败:', error);
});
}
this.eventSource.close(); this.eventSource.close();
this.eventSource = null; this.eventSource = null;
} }
@ -1052,6 +1061,20 @@ class RunSimulation extends HTMLElement {
this.resetUIAfterCompletion(); this.resetUIAfterCompletion();
} }
} }
// 添加组件销毁时的清理方法
disconnectedCallback() {
// 清理SSE连接和相关资源
this.closeEventSource();
// 重置所有状态
this.currentSimulationId = null;
this.reconnectAttempts = 0;
this.scenarioFiles = [];
this.currentScenario = null;
this.modelGroups = [];
this.services = [];
}
} }
customElements.define('run-simulation', RunSimulation); customElements.define('run-simulation', RunSimulation);

View File

@ -123,26 +123,27 @@ router.get('/simulation-output/:id', async (req, res) => {
}); });
// 将进程添加到runningSimulations // 将进程添加到runningSimulations
runningSimulations.set(simulationId, { const simulation = runningSimulations.get(simulationId) || {
pid: processInfo.pid, pid: processInfo.pid,
startTime: new Date(processInfo.start_time).getTime(), startTime: new Date(processInfo.start_time).getTime(),
output: '', output: '',
errorOutput: '', errorOutput: '',
logFile: processInfo.log_file logFile: processInfo.log_file
}); };
runningSimulations.set(simulationId, simulation);
// 使用tail命令来跟踪日志文件 // 使用tail命令来跟踪日志文件
const tailProcess = spawn('tail', ['-f', processInfo.log_file], { const tailProcess = spawn('tail', ['-f', processInfo.log_file], {
stdio: ['ignore', 'pipe', 'pipe'] stdio: ['ignore', 'pipe', 'pipe']
}); });
// 保存tail进程引用
simulation.tailProcess = tailProcess;
// 收集标准输出 // 收集标准输出
tailProcess.stdout.on('data', (data) => { tailProcess.stdout.on('data', (data) => {
const chunk = data.toString('utf8'); const chunk = data.toString('utf8');
const simulation = runningSimulations.get(simulationId); simulation.output += chunk;
if (simulation) {
simulation.output += chunk;
}
// 推送到SSE客户端 // 推送到SSE客户端
sendSSEMessage(simulationId, 'output', { sendSSEMessage(simulationId, 'output', {
@ -153,11 +154,17 @@ router.get('/simulation-output/:id', async (req, res) => {
// 当客户端断开连接时清理 // 当客户端断开连接时清理
req.on('close', () => { req.on('close', () => {
tailProcess.kill(); if (simulation.tailProcess) {
simulation.tailProcess.kill();
simulation.tailProcess = null;
}
}); });
// 当tail进程结束时 // 当tail进程结束时
tailProcess.on('close', (code) => { tailProcess.on('close', (code) => {
if (simulation.tailProcess === tailProcess) {
simulation.tailProcess = null;
}
runningSimulations.delete(simulationId); runningSimulations.delete(simulationId);
sendSSEMessage(simulationId, 'status', { sendSSEMessage(simulationId, 'status', {
running: false, running: false,
@ -316,7 +323,7 @@ router.post('/run-simulation', async (req, res) => {
scenario_file: args[0] scenario_file: args[0]
}); });
// 保存到运行中的仿真Map // 保存到运行中的仿真Map但不启动tail进程
runningSimulations.set(simulationId, { runningSimulations.set(simulationId, {
pid: processId, pid: processId,
startTime: Date.now(), startTime: Date.now(),
@ -332,37 +339,6 @@ router.post('/run-simulation', async (req, res) => {
simulationId: processId.toString(), simulationId: processId.toString(),
scenarioFile: args[0] scenarioFile: args[0]
}); });
// 启动一个后台任务来监控日志文件
const tailProcess = spawn('tail', ['-f', logFile], {
stdio: ['ignore', 'pipe', 'pipe']
});
// 收集输出
tailProcess.stdout.on('data', (data) => {
const chunk = data.toString('utf8');
const simulation = runningSimulations.get(simulationId);
if (simulation) {
simulation.output += chunk;
}
// 推送到SSE客户端
sendSSEMessage(simulationId, 'output', {
type: 'stdout',
data: chunk
});
});
// 当tail进程结束时
tailProcess.on('close', (code) => {
runningSimulations.delete(simulationId);
// 删除数据库中的进程记录
deleteXNEngineProcess(processId);
sendSSEMessage(simulationId, 'status', {
running: false,
message: '仿真进程已结束'
});
});
} else { } else {
// 进程启动失败或不是XNEngine进程 // 进程启动失败或不是XNEngine进程
await deleteXNEngineProcess(processId); await deleteXNEngineProcess(processId);
@ -500,4 +476,27 @@ router.get('/check-xnengine', async (req, res) => {
} }
}); });
// 添加清理仿真资源的接口
router.post('/cleanup-simulation/:id', (req, res) => {
const simulationId = req.params.id;
// 清理该仿真ID对应的所有资源
if (runningSimulations.has(simulationId)) {
// 清理tail进程
const simulation = runningSimulations.get(simulationId);
if (simulation.tailProcess) {
try {
simulation.tailProcess.kill();
} catch (error) {
console.error('清理tail进程失败:', error);
}
}
// 清理其他资源
runningSimulations.delete(simulationId);
}
res.json({ success: true, message: '仿真资源已清理' });
});
module.exports = router; module.exports = router;