Node.js 中如何运行定时(cron)任务?
在 Node.js 里跑 cron 定时任务:node-cron 安装与 schedule 用法、cron 表达式示例、setInterval 替代方案、进程常驻注意事项与 FAQ。
用 node-cron 库:npm install node-cron@4 后,cron.schedule("表达式", 函数) 注册任务即可,进程运行期间任务按点触发。 只需固定间隔的话,内置 setInterval 也能顶,但表达不了"每天凌晨"这类日历语义。
1. 安装
npm install node-cron@4
2. 完整示例:每天零点清理临时文件
const fs = require('fs');
const path = require('path');
const cron = require('node-cron');
const TMP_DIR = path.join(__dirname, 'tmp');
async function cleanup() {
const entries = await fs.promises.readdir(TMP_DIR, { withFileTypes: true });
let count = 0;
for (const entry of entries) {
if (!entry.isFile()) continue; // 仅普通文件;目录与链接不处理
await fs.promises.unlink(path.join(TMP_DIR, entry.name));
count++;
}
console.log(`清理完成,共 ${count} 个文件`);
}
// 此 tmp 目录须由应用控制,避免不可信并发替换路径
cron.schedule('0 0 * * *', async () => {
try { await cleanup(); }
catch (error) { console.error('清理失败:', error); }
}, { noOverlap: true }); // 只约束本进程的该任务,不是分布式锁
表达式是标准五字段(分 时 日 月 星期),node-cron 也支持六字段(首位为秒)。
3. 常用写法
cron.schedule('*/5 * * * *', task); // 每 5 分钟
cron.schedule('30 2 * * 1', task); // 每周一 2:30
cron.schedule('*/10 * * * * *', task); // 每 10 秒(六字段格式)
// 手动控制
const job = cron.createTask('0 * * * *', task); // v4 创建但不自动启动
job.start(); // 启动
job.stop(); // 停止
4. 注意事项
- 进程必须常驻:node-cron 是进程内调度器,进程退出任务就没了。生产环境用 PM2、systemd 或容器保活。
- 单实例才安全:多副本部署时每份进程都会触发,任务会重复执行——用分布式锁或让任务只跑在指定实例上。
- 时区:
cron.schedule('0 0 * * *', fn, { timezone: 'Asia/Shanghai' })显式指定,避免容器里默认 UTC 造成的"差 8 小时"。
验证任务时,记录调度时区、计划时间、执行编号和最终结果;只有实际异步操作结束后才写完成记录。重启与多副本场景分别演练,核对是否漏跑或重复运行。
常见问题(FAQ)
Q:node-cron 和系统 crontab 选哪个?
A:任务逻辑离不开 Node 代码(要 require 业务模块)用 node-cron;任务本身是独立脚本、运维要统一管理调度,系统 crontab 也可调用 require 业务模块的一次性 Node 脚本;该入口只运行 cleanup 一次、处理错误后退出,不能再次注册长期 cron.schedule。
Q:进程重启会错过执行吗?
A:会,node-cron 不做错过补偿(misfire)。关键任务启动时先检查"上次执行时间",按业务设计持久执行记录、幂等和补偿策略,不能仅按时间无条件补跑一次就保证不重不漏。
Q:能动态修改调度吗?
A:不能改已有任务的表达式,但可以 job.stop() 后用新表达式重新 schedule。