diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 3ee549c..031aa43 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/XNSimHtml/components/run-simulation.js b/XNSimHtml/components/run-simulation.js index 2847d7c..2c6185f 100644 --- a/XNSimHtml/components/run-simulation.js +++ b/XNSimHtml/components/run-simulation.js @@ -635,6 +635,15 @@ class RunSimulation extends HTMLElement { // 关闭SSE连接 closeEventSource() { 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 = null; } @@ -1052,6 +1061,20 @@ class RunSimulation extends HTMLElement { 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); \ No newline at end of file diff --git a/XNSimHtml/routes/run-simulation.js b/XNSimHtml/routes/run-simulation.js index f973f67..c176b77 100644 --- a/XNSimHtml/routes/run-simulation.js +++ b/XNSimHtml/routes/run-simulation.js @@ -123,26 +123,27 @@ router.get('/simulation-output/:id', async (req, res) => { }); // 将进程添加到runningSimulations - runningSimulations.set(simulationId, { + const simulation = runningSimulations.get(simulationId) || { pid: processInfo.pid, startTime: new Date(processInfo.start_time).getTime(), output: '', errorOutput: '', logFile: processInfo.log_file - }); + }; + runningSimulations.set(simulationId, simulation); // 使用tail命令来跟踪日志文件 const tailProcess = spawn('tail', ['-f', processInfo.log_file], { stdio: ['ignore', 'pipe', 'pipe'] }); + // 保存tail进程引用 + simulation.tailProcess = tailProcess; + // 收集标准输出 tailProcess.stdout.on('data', (data) => { const chunk = data.toString('utf8'); - const simulation = runningSimulations.get(simulationId); - if (simulation) { - simulation.output += chunk; - } + simulation.output += chunk; // 推送到SSE客户端 sendSSEMessage(simulationId, 'output', { @@ -153,11 +154,17 @@ router.get('/simulation-output/:id', async (req, res) => { // 当客户端断开连接时清理 req.on('close', () => { - tailProcess.kill(); + if (simulation.tailProcess) { + simulation.tailProcess.kill(); + simulation.tailProcess = null; + } }); // 当tail进程结束时 tailProcess.on('close', (code) => { + if (simulation.tailProcess === tailProcess) { + simulation.tailProcess = null; + } runningSimulations.delete(simulationId); sendSSEMessage(simulationId, 'status', { running: false, @@ -316,7 +323,7 @@ router.post('/run-simulation', async (req, res) => { scenario_file: args[0] }); - // 保存到运行中的仿真Map + // 保存到运行中的仿真Map,但不启动tail进程 runningSimulations.set(simulationId, { pid: processId, startTime: Date.now(), @@ -332,37 +339,6 @@ router.post('/run-simulation', async (req, res) => { simulationId: processId.toString(), 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 { // 进程启动失败或不是XNEngine进程 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; \ No newline at end of file