如何实现Node.js服务定时自动重启 每10秒刷新API拉取的最新数据
温湿度Node.js服务10秒刷新数据的实现方案
核心判断
你提到的两种实现方向都是走了弯路:既不需要把全量app.js代码封装靠循环定时重启实现刷新,也不需要引入crontab这类系统级调度工具,纯Node.js内置能力配合现有forever工具,就能稳定实现需求。
你当前代码存在的基础问题
- 末尾定义的匿名async函数没有被实际调用:你现在的代码只是写完了函数逻辑,没有加执行括号触发运行,直接启动的话不会有任何服务启动、API调用的动作
- 数据拉取逻辑和服务启动绑死:就算修了函数调用的问题,温湿度数据只会在服务启动的那一刻拉取一次,后续不管服务跑多久,页面展示的永远是启动瞬间的旧值,完全达不到“始终最新”的效果
两种思路的可行性辨析
不推荐:全量代码封装+定时重启
- 如果你把整个服务逻辑放到setInterval里定时执行,第二次循环就会触发
EADDRINUSE端口占用错误——因为express的app.listen是长驻监听逻辑,重复调用会直接报错 - 定时重启进程的运行开销极高,还会出现用户访问服务时刚好碰到重启断档的问题
完全没必要:crontab系统调度
- crontab的设计定位是跑独立的一次性离线任务,不适合承载长驻Web服务
- 跨平台兼容性差,Windows环境没有原生crontab能力,对新手的学习成本很高
推荐的落地实现
核心原则是Web服务长驻只启动一次,数据拉取逻辑独立定时执行:
- 把温湿度API的拉取逻辑抽成独立的可重复执行函数
- 用全局变量存储最新拉取到的温湿度值,每次拉取完成就更新这个变量
- express服务只在启动阶段初始化一次,监听端口的动作永远不重复执行
- 服务启动后先立刻拉一次数据,再用
setInterval设置10秒的刷新周期,持续更新全局存储的最新值 - 做代码变更时的自动重启,直接用forever的文件监听能力实现就行,和数据刷新逻辑完全解耦
优化后的参考代码:
const something = require("some node module"); const express = require("express"); const bodyParser = require("body-parser"); // 初始化全局存储最新数据的变量 let latestData = { temperature: null, humidity: null } // 把拉取数据的逻辑抽成独立函数 async function refreshDeviceData() { try { const connection = new something({ email: "email", password: "password", region: "us", }); const temperatureRes = await connection.getDeviceCurrentTemperature("some ID"); const humidityRes = await connection.getDeviceCurrentHumidity("some ID"); // 拉到新数据就覆盖全局变量 latestData.temperature = temperatureRes.temperature; latestData.humidity = humidityRes.humidity; console.log(`数据已刷新,当前温度: ${latestData.temperature} °C, 湿度: ${latestData.humidity} %`); } catch (err) { // 拉取失败不要让整个服务崩掉,打日志就行 console.log("数据刷新失败,错误信息:", err.message); } } // 初始化express服务(只执行一次) const app = express(); app.use(express.static("public")); app.set("view engine", "ejs"); app.set("views", __dirname + "/views"); app.use(bodyParser.urlencoded({ extended: false })); app.get("/", (req, res) => { // 渲染的时候直接取全局存的最新数据 res.render("index", { temp: latestData.temperature, hum: latestData.humidity }); }); // 启动服务逻辑 async function startService() { // 启动后立刻先拉一次数据,避免刚启动的时候页面是空的 await refreshDeviceData(); // 设置10秒周期刷新 setInterval(refreshDeviceData, 10 * 1000); // 启动监听,只执行一次 app.listen(8080, () => { console.log("服务已启动,端口8080"); }); } // 真正执行启动函数 startService();
实现细节注意点
- 所有API调用的逻辑都要加
try/catch捕获异常,避免单次调用失败导致整个服务崩溃退出 - 全局存储的数据量不要设太大,存当前最新的温湿度值就够,避免内存泄漏
- 不要把express初始化、端口监听的代码放到定时执行的函数里,否则必然触发端口占用报错
内容的提问来源于stack exchange,提问作者PhGa90
相关产品推荐
相关产品推荐

