NestJS如何从指定start_date时间启动动态Cron定时任务
实现方式
Cron本身的预设表达式(比如CronExpression.EVERY_WEEK)默认从当前时间开始匹配周期,要实现从指定start_date启动并按规则重复,直接用CronJob构造函数自带的startTime配置参数,搭配自定义生成的周期Cron表达式即可,不需要额外写延迟启动逻辑。
具体实现步骤
- 第一步:根据
occur字段值和start_date的时间信息,生成匹配周期的自定义Cron表达式
不同周期的表达式生成规则:- weekly(周度重复):提取
start_date的分钟、小时、星期值,生成格式为分 时 * * 星期值的表达式,例如start_date为2024-10-01 14:30(周二,对应cron星期值2),最终表达式为30 14 * * 2,代表每周二14:30执行 - monthly(月度重复):提取
start_date的分钟、小时、当月日期值,生成格式为分 时 日期值 * *的表达式,例如start_date为2024-10-05 09:00,最终表达式为0 9 5 * *,代表每月5号09:00执行 - yearly(年度重复):提取
start_date的分钟、小时、当月日期、月份值,生成格式为分 时 日期值 月份值 *的表达式,例如start_date为2024-12-25 00:00,最终表达式为0 0 25 12 *,代表每年12月25日00:00执行
- weekly(周度重复):提取
- 第二步:创建CronJob时传入
start_date作为startTime参数,指定任务最早生效时间,早于该时间点即使匹配cron规则也不会触发 - 第三步:配置正确的时区参数,避免服务器默认时区和业务时区不一致导致执行时间偏移
代码示例
import { CronJob } from 'cron'; /** * 根据起始时间和重复周期生成cron表达式 * @param startDate 提醒起始时间 * @param occur 重复周期 */ function generateCronExpression(startDate: Date, occur: 'weekly' | 'monthly' | 'yearly'): string { const minute = startDate.getMinutes(); const hour = startDate.getHours(); switch (occur) { case 'weekly': // cron星期取值范围0-6,0代表周日 const weekDay = startDate.getDay(); return `${minute} ${hour} * * ${weekDay}`; case 'monthly': const dayOfMonth = startDate.getDate(); return `${minute} ${hour} ${dayOfMonth} * *`; case 'yearly': const targetDay = startDate.getDate(); // cron月份取值范围1-12,Date.getMonth()返回0-11,需要+1转换 const targetMonth = startDate.getMonth() + 1; return `${minute} ${hour} ${targetDay} ${targetMonth} *`; default: throw new Error('不支持的重复周期类型'); } } // 初始化定时任务逻辑 const reminderName = '你的提醒name字段值'; const startDate = new Date('你的start_date字段值'); const occur = 'weekly'; // 你的occur字段值 const cronExpression = generateCronExpression(startDate, occur); const job = new CronJob( cronExpression, () => { // 此处写提醒触发的业务逻辑 console.log('触发提醒'); }, null, true, 'Asia/Shanghai', // 替换为你业务使用的时区,国内一般用Asia/Shanghai null, null, startDate // 关键配置:指定任务最早生效时间 ); // 注册任务到调度器 this.schedulerRegistry.addCronJob(`reminder_${reminderName}`, job); job.start();
注意事项
- 如果传入的
start_date早于当前时间,任务会自动匹配下一个符合cron规则的时间点执行,不会补跑历史任务 - 注册任务时建议给任务名加业务前缀(比如示例里的
reminder_),避免和其他定时任务重名被覆盖 - 不要使用
CronExpression预设的周/月/年常量,这类常量没有绑定start_date对应的具体时分、周/月/日信息,会导致执行时间不符合预期
内容的提问来源于stack exchange,提问作者Subash
相关产品推荐
相关产品推荐

