Node.js 定时任务:使用 node-cron 调度作业
FreeGuideOnline
最新
2026-06-15
什么是 node-cron?
node-cron 是一个轻量级的 Node.js 库,允许你按照类似 Unix cron 的时间表执行定时任务。你可以用它来实现数据备份、定期清理日志、发送周期性邮件等后台作业,而无需依赖操作系统级别的 cron。
安装与准备
确保已安装 Node.js(v12 以上)。在项目根目录执行:
npm install node-cron
如果需要 TypeScript 类型:
npm install -D @types/node-cron
快速入门
创建 scheduler.js,写入最简单的定时任务:
const cron = require('node-cron');
// 每分钟执行一次
const task = cron.schedule('* * * * *', () => {
console.log('每分钟执行的任务,时间:', new Date().toLocaleTimeString());
});
console.log('定时任务已启动');
运行 node scheduler.js,终端将每分钟打印一条日志。
Cron 表达式详解
node-cron 使用 5 或 6 个字段的 cron 表达式(支持秒级精度时用 6 位):
* * * * * * (6 位:秒 分 时 日 月 星期)
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ └─── 星期 (0-7,0 和 7 都表示周日)
│ │ │ │ └─────── 月份 (1-12)
│ │ │ └─────────── 日期 (1-31)
│ │ └─────────────── 小时 (0-23)
│ └─────────────────── 分钟 (0-59)
└─────────────────────── 秒 (0-59) 可选
不提供第 6 位时,任务最小粒度为“分钟”。
常用表达式示例
| 表达式 | 含义 |
|---|---|
* * * * * |
每分钟 |
*/5 * * * * |
每 5 分钟 |
0 * * * * |
每小时整点 |
0 0 * * * |
每天午夜 |
0 8 * * 1-5 |
工作日早上 8 点 |
30 3 1 * * |
每月 1 号凌晨 3:30 |
0 0 1 1 * |
每年 1 月 1 号零点 |
0 30 14 * * 6 |
每周六下午 2:30 |
*/2 * * * * * |
每 2 秒(需要开启秒级支持) |
可读别名
node-cron 支持一些预设字符串:
@yearly或@annually→ 每年 1 月 1 日零点@monthly→ 每月 1 号零点@weekly→ 每周日零点@daily或@midnight→ 每天零点@hourly→ 每小时整点
cron.schedule('@daily', () => {
console.log('每天执行');
});
基本用法与控制
启动与停止
const task = cron.schedule('* * * * *', () => {
console.log('运行中...');
});
// 启动任务(默认 schedule 后自动启动,也可手动控制)
task.start();
// 停止任务
setTimeout(() => {
task.stop();
console.log('任务已停止');
}, 120000); // 2 分钟后停止
验证表达式
const valid = cron.validate('*/5 * * * *'); // true
console.log(valid);
获取下次执行时间(需手动计算)
node-cron 本身不直接提供,但可以用 cron-parser 库解析:
npm install cron-parser
const parser = require('cron-parser');
const interval = parser.parseExpression('*/10 * * * *');
console.log('下次执行:', interval.next().toISOString());
进阶场景
结合时区
从 3.0 版本开始,node-cron 支持 timezone 选项:
const task = cron.schedule('0 9 * * *', () => {
console.log('北京时间早上9点执行');
}, {
scheduled: true,
timezone: 'Asia/Shanghai'
});
需要 Intl 支持,Node.js 13+ 默认可用。
任务防重叠
如果任务执行时间超过了间隔,可能导致并行执行。可使用一个简单锁:
let running = false;
cron.schedule('* * * * *', async () => {
if (running) return;
running = true;
console.log('开始执行耗时任务...');
await new Promise(resolve => setTimeout(resolve, 5000)); // 模拟 5 秒任务
console.log('任务完成');
running = false;
});
优雅关闭
在进程退出时停止所有任务:
const tasks = [];
tasks.push(cron.schedule('* * * * *', () => {}));
process.on('SIGINT', () => {
tasks.forEach(t => t.stop());
console.log('所有定时任务已停止,进程退出');
process.exit();
});
秒级任务
需要传入 scheduled 选项并将表达式设为 6 个字段:
cron.schedule('*/10 * * * * *', () => {
console.log('每 10 秒执行');
}, {
scheduled: true
});
常见错误与调试
- 任务不运行:检查是否调用
start(),默认schedule会自动启动,但如果使用了{scheduled: false}则需手动启动。 - 时区问题:服务器时区与预期不符,务必显式指定
timezone。 - 任务阻塞事件循环:避免在任务中执行同步的长时间计算,应使用异步模式或子进程。
- 月份/星期同时指定:当日期和星期都被指定时,cron 的行为是“或”关系(即满足日期或星期之一即触发),这可能会导致意外触发。如需严格“且”关系,需自行在回调中添加日期判断。
完整示例:日志清理任务
const cron = require('node-cron');
const fs = require('fs');
const path = require('path');
const LOG_DIR = './logs';
const MAX_AGE_DAYS = 7;
function cleanOldLogs() {
fs.readdir(LOG_DIR, (err, files) => {
if (err) {
console.error('读取日志目录失败', err);
return;
}
const now = Date.now();
files.forEach(file => {
const filePath = path.join(LOG_DIR, file);
fs.stat(filePath, (err, stats) => {
if (err) return;
const ageDays = (now - stats.mtimeMs) / (1000 * 60 * 60 * 24);
if (ageDays > MAX_AGE_DAYS) {
fs.unlink(filePath, err => {
if (err) console.error('删除失败:', filePath);
else console.log('已删除旧日志:', file);
});
}
});
});
});
}
// 每天凌晨3点清理7天前的日志
cron.schedule('0 3 * * *', cleanOldLogs, {
timezone: 'Asia/Shanghai'
});
console.log('日志清理调度已启动');
总结
node-cron 提供了在 Node.js 应用中执行定时任务的简洁方案。掌握 cron 表达式的写法、熟悉任务的启停控制以及处理时区和并发问题,能让你在绝大多数场景下轻松实现作业调度。对于更复杂的需求(如持久化、集群),可考虑组合 cron-parser 或升级到专业的任务队列库(如 Bull、Agenda)。