前言
nest开发过程中,难免会碰到类似于定时任务之类的功能, Nest提供了@nestjs/schedule包,它集成了流行的Node.js 的cron包,以便于我们处理应用中的定时任务
安装依赖
首先我们需要安装 @nestjs/schedule
//不动态设置job不用导入 cron
yarn add @nestjs/schedule cron
导入到 AppModule 中, 使用 forRoot初始化我们的声明式定时任务,其可以初始化我们声明式的 cron jobs、timeouts和intervals任务
@Module({
imports: [
ScheduleModule.forRoot()
],
})
export class AppModule {}
定时任务介绍
创建一个声明式基础定时任务
创建一个声明式的定时任务
//每天的9点运行一次,时间跟运行系统的时区有关系
@Cron('* * 9 * * *')
async remindUsers() {}
nestjs 的 cron表达式介绍
cron表达式,这个跟前面介绍的 cron表达式有点像,但是又不完全一样,其有六个选项,第一个是从秒开始的
* * * * * * 表示 秒 分 时 日 月 周,不同种类中间使用空格隔开
* 按照顺序分别代表每秒、每分、每时...
- 星号
*例如: * * * * * * 表示每秒都运行 - 单个节点 例如: * * 9 * * * 表示每天的9点运行
- 范围区间
-例如: 1-3 * * * * * 表示每分钟的 1,2,3秒分别运行一次 - 范围多个节点
,例如:1,3 * * * * 表示每分钟的 1,3 秒分别运行一次 - 步长(
*/x)例如:*/30 * * * * 表示每 30 秒 运行一次
cron表达式设置时区等参数
@Cron('* * 11 * * *', {
name: 'wxchat_remind', //命名有利于后续动态获取访问和更新,非必填
timeZone: 'Asia/Shanghai', //时区,设置时区,和下面的utcOffset二选一
// utcOffset: 8 * 60, //根据utc偏移精确到分
})
async remindUsers() {}
声明式interval、timeout
声明式设置延迟任务,也是随着系统启动的开始运行,单位毫秒(ms),可以带名字,也可以不带名字,带名字的后续可以通过名字查询、停止、启动
//单位ms,每间隔指定ms运行一次
// @Interval(5000)
@Interval('test_interval_task', 2000)
async intervalTask() {
console.log('text_interval');
}
//单位ms,间隔指定ms执行一次结束
@Timeout(3000)
@Timeout('test_timeout', 8000)
handleTimeout() {
console.log('test_timeout');
}
获取、操作定时任务
前面讲了,如果要后续操作定时任务,那么需要给一个名字,我们可以通过 注入 SchedulerRegistry 的方式操作定时任务
constructor(private schedulerRegistry: SchedulerRegistry) {}
可以通过 getCronJob、getInterval、getTimeout方法获取我们的计时任务,还可以停止、继续我们的定时任务
也可以通过 deleteCronJob、deleteInterval、deleteTimeout删除我们的声明时注册的定时任务,删除也就意味着定时任务也停止了,取消注册了,不能够通过前面方法获取到该任务了
const job = this.schedulerRegistry.getCronJob('wxchat_appy_remind'); //找不到直接抛出异常
job.stop(); //停止声明的的任务
// job.start(); //如果开始其disable状态,可以通过start启用
// const interval = this.schedulerRegistry.getInterval('test_interval_task');
// clearInterval(interval)
// this.schedulerRegistry.deleteInterval('test_interval_task'); //删除该 interval,删除后自然不会执行
// const timeout = this.schedulerRegistry.getTimeout('test_timeout');
// clearTimeout(timeout);
// this.schedulerRegistry.deleteTimeout('test_timeout'); //删除该 interval,删除后自然不会执行
动态创建定时任务
有时我们需要动态创建定时任务,怎么办呢,和前面的删除类似,通过 SchedulerRegistry 将定时任务注册进去就行了, 如下所示,注册定时任务
//假设只改动一个s
addCronJob(name: string, cron: string) {
const job = new CronJob(cron, () => {
console.log('动态cron 123');
});
this.schedulerRegistry.addCronJob(
name,
new CronJob(`${seconds} * * * * *`, () => {
console.log('动态cron 123');
}),
);
//默认不启动,可以直接启动,也可以后续手动获取定时任务并启动
job.start();
}
addInterval(name: string, milliseconds: number) {
const interval = setInterval(() => {
console.log('动态interval');
}, milliseconds);
this.schedulerRegistry.addInterval(name, interval);
}
addTimeout(name: string, milliseconds: number) {
const timeout = setTimeout(() => {
console.log('动态timeout');
}, milliseconds);
this.schedulerRegistry.addTimeout(name, timeout);
}
调用我们的定时任务
this.addCronJob('dynamic_cron_job', '*/2 * * * * *');
this.addInterval('dynami_interval_job', 1000);
this.addTimeout('dynami_timeout_job', 3000);
删除动态创建的定时任务,和删除声明式的一样,只不过由于其能动态创建,比较适合动态设置定时任务的需求
//有需要手动启动的定时任务,可以和前面一样,查询启动即可
const dynamicJob =
this.schedulerRegistry.getCronJob('dynamic_cron_job'); //找不到直接抛出异常
dynamicJob.start(); //启动,这个动态创建的无法停止,直接delete清理即可
//删除定时任务
this.schedulerRegistry.deleteCronJob('dynamic_cron_job');
this.schedulerRegistry.deleteInterval('dynami_interval_job');
this.schedulerRegistry.deleteTimeout('dynami_timeout_job');
设置一下我们的时区环境变量
直接在 main 函数设置我们的时区环境变量即可,这样我们 nestjs 内部的一些涉及时间的,例如:定时任务等则都会生效,无需刻意设置时区
ps:对于一些通用性的时间相关组件则无效,因为其通用,是根据系统时区来的,例如:dayjs、moment
//直接在main函数中设置我们的时区系统变量即可
//设置我们环境变量时区timeZone为中国上海,在我们nestjs内部一些会有效,dayjs、moment这些通用的自然无效
process.env.TZ = 'Asia/Shanghai';
ps:重要的话说两遍,设置时区环境变量只对nestjs内部使用它的有效,通用的时间组件无效