如何重构Node.js代码,使应用在每日任务结束后等待下一次Cron调度?
Node.js股票数据应用重构方案
核心问题
你的问题本质是WebSocket服务生命周期和Cron任务未解耦,导致清理操作后旧连接无法正常终止,状态重置逻辑依赖main()递归引发实例堆积,最终客户端无限重连直到崩溃。
重构步骤
1. 拆分模块,解耦核心逻辑
把WebSocket服务、数据收集、状态管理拆成独立可控的单元,避免所有逻辑堆在main()里导致状态耦合:
// 模块级全局状态(替代局部变量,方便跨任务访问) let wsServer = null; let isFirstCall = true; let stockDataList = []; // 启动WebSocket服务 function startWebSocketService() { const WebSocket = require('ws'); wsServer = new WebSocket.Server({ port: 你使用的端口 }); wsServer.on('connection', (ws) => { // 推送现有股票数据 if (stockDataList.length) { ws.send(JSON.stringify(stockDataList)); } // 捕获连接错误,避免单个客户端崩溃拖垮整个服务 ws.on('error', (err) => { console.error('客户端连接异常:', err); }); }); } // 关闭WebSocket服务(关键:主动终止所有连接) function stopWebSocketService() { if (!wsServer) return; // 先给所有客户端发送明确关闭信号,告知无需立即重连 wsServer.clients.forEach(client => { if (client.readyState === client.OPEN) { client.close(1000, '每日数据清理完成,次日6点后可重新连接'); } }); // 关闭服务端实例 wsServer.close(err => { if (err) console.error('WebSocket服务关闭失败:', err); wsServer = null; // 重置实例引用 }); } // 股票数据收集逻辑 async function fetchStockData() { // 替换成你的API查询逻辑 stockDataList = await 你的API查询函数(); isFirstCall = false; } // 每日20:05清理任务 const dailyCleanup = require('node-cron').schedule('0 5 20 * * *', () => { stopWebSocketService(); // 先关WS stockDataList = []; // 清空数据 isFirstCall = true; // 重置状态 console.log('每日清理完成,等待次日调度'); }); // 每日6:00启动任务 const dailyStart = require('node-cron').schedule('0 0 6 * * *', async () => { await fetchStockData(); // 收集数据 startWebSocketService(); // 启动WS console.log('次日任务启动,WebSocket服务已就绪'); }); // 应用初始化(首次启动执行) async function initApp() { await fetchStockData(); startWebSocketService(); console.log('应用初始化完成'); } initApp();
2. 关键修复说明
- WebSocket实例全局可控:通过模块级变量
wsServer维护服务实例,清理任务可以直接调用stopWebSocketService()主动关闭所有连接,从根源解决客户端无限重连的问题 - 状态变量独立管理:
isFirstCall和stockDataList改成模块级,清理时直接重置,不需要依赖main()递归调用 - Cron任务职责分离:启动任务负责数据收集+WS启动,清理任务负责WS关闭+状态重置,互不干扰,避免实例堆积
- 错误防护:给WebSocket连接添加错误捕获,避免单个客户端的异常导致整个应用崩溃
3. 为什么之前调用main()失败?
直接递归调用main()会重复创建Cron任务、WebSocket服务实例,旧的服务实例不会被销毁,客户端会一直连接旧实例,同时新实例的状态和旧实例冲突,最终导致内存泄漏和重连异常。
4. 额外优化
- 给所有关键操作添加日志,方便排查问题
- 可以给客户端的重连逻辑添加延迟,比如收到关闭信号后,等到次日6点再尝试重连
- 给Cron任务添加错误捕获,避免任务执行失败导致应用崩溃
内容的提问来源于stack exchange,提问作者ADSquared
相关产品推荐
相关产品推荐

