Node.js中限制重复分析请求及终止分析的实现方案咨询
Node.js 游戏分析任务:防重复请求与终止方案
一、阻止同一游戏的重复分析请求
用全局Map跟踪当前运行的任务是可行的方案,比数组/普通对象更安全(避免原型链污染)、操作更便捷。每个游戏名称对应一个包含终止控制器和运行状态的对象,路由请求时先检查Map状态:
// 全局任务跟踪容器,key=游戏名称,value={ controller: AbortController, isRunning: boolean } const runningTasks = new Map(); app.get('/analyzeGame/:name', async (req, res) => { const gameName = req.params.name; // 检查是否已有正在运行的同游戏任务 const existingTask = runningTasks.get(gameName); if (existingTask?.isRunning) { return res.send(`游戏 ${gameName} 正在分析中,请稍后再试`); } // 创建终止控制器,标记任务为运行中 const controller = new AbortController(); runningTasks.set(gameName, { controller, isRunning: true }); // 立即返回响应,不等待分析完成 res.send(`starting to analyze ${gameName}`); // 后台执行分析任务 try { await analyzeGame(gameName, controller.signal); } catch (err) { if (err.name === 'AbortError') { console.log(`游戏 ${gameName} 分析任务已终止`); } else { console.error(`分析游戏 ${gameName} 出错:`, err); } } finally { // 任务结束(成功/失败/终止),从Map中移除 runningTasks.delete(gameName); } });
二、终止正在执行的分析任务
通过AbortController实现任务终止,配合/stopAnalyzing/:name路由触发终止信号,同时要求分析函数在关键步骤检查终止状态:
1. 终止路由实现
app.get('/stopAnalyzing/:name', (req, res) => { const gameName = req.params.name; const task = runningTasks.get(gameName); if (!task || !task.isRunning) { return res.send(`游戏 ${gameName} 没有正在运行的分析任务`); } // 触发终止信号,标记任务为已停止 task.controller.abort(); task.isRunning = false; res.send(`已终止游戏 ${gameName} 的分析任务`); });
2. 支持终止的分析函数
分析函数需要在耗时步骤(循环、异步操作前)检查终止信号,收到信号后立即停止执行并清理资源:
async function analyzeGame(gameName, signal) { // 初始检查:若已终止直接抛出错误 if (signal.aborted) throw new Error('AbortError'); // 监听终止事件,执行资源清理 signal.addEventListener('abort', () => { console.log(`终止游戏 ${gameName} 分析,开始清理资源`); // 这里可以添加关闭数据库连接、释放临时文件等逻辑 }); // 模拟耗时分析流程 const gameData = await fetchGameRawData(gameName); for (const playerData of gameData) { // 每处理一个玩家前检查终止状态 if (signal.aborted) throw new Error('AbortError'); await analyzePlayerData(playerData); } // 分析完成后存储结果 await saveAnalysisToDB(gameName, finalResult); }
关于全局变量的补充说明
- 单进程Node.js服务中,用Map完全可靠,是轻量高效的方案;
- 如果是多进程(cluster模式)或分布式部署,全局Map无法跨进程共享,此时需要用Redis等外部存储:用键值对跟踪任务状态,用发布订阅模式传递终止指令。
内容的提问来源于stack exchange,提问作者user13674310
相关产品推荐
相关产品推荐

