nestjs-定时任务以及时区环境变量设置

481 阅读4分钟

前言

nest开发过程中,难免会碰到类似于定时任务之类的功能, Nest提供了@nestjs/schedule包,它集成了流行的Node.js 的cron包,以便于我们处理应用中的定时任务

安装依赖

首先我们需要安装 @nestjs/schedule

//不动态设置job不用导入 cron
yarn add @nestjs/schedule cron

导入到 AppModule 中, 使用 forRoot初始化我们的声明式定时任务,其可以初始化我们声明式的 cron jobstimeoutsintervals任务

@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内部使用它的有效通用的时间组件无效