Skip to content

好的,我们来探讨一个能让你的应用“活”起来,可以自动执行周期性任务的强大功能:任务调度 (Task Scheduling)。这就像是为你的应用设置了一系列精准的“智能闹钟”,让它在无人干预的情况下,也能按时完成各种预设的工作。

为你的应用设置“智能闹钟”:NestJS 任务调度完全指南

想象你的应用是一位勤勤恳恳的办公室文员。

他的日常工作除了处理即时到来的任务(响应 HTTP 请求)之外,还有很多需要在特定时间按固定周期完成的例行公事:

  • 每天午夜:生成前一天的销售报告。(Cron Job)
  • 每隔一小时:清理一次临时文件夹,删除过期文件。(Interval)
  • 在应用启动 5 分钟后:发送一封“系统已启动”的通知邮件。(Timeout)

如果每次都需要你手动登录服务器去触发这些操作,那简直是一场灾难。你需要一个全自动的“日程管理系统”,让他可以自己“看表”,到点就自动完成这些任务。

在 NestJS 中,这个“日程管理系统”就是由官方提供的 @nestjs/schedule 模块。它将著名的 node-cron 库与 NestJS 的依赖注入系统完美地结合在了一起。

1. 第一步:安装“日程管理系统” (@nestjs/schedule)

第一步:安装必要的依赖

bash
npm install @nestjs/schedule

第二步:在 AppModule 中注册 ScheduleModule

我们需要在根模块中,使用 ScheduleModule.forRoot() 来启动这个调度引擎。

src/app.module.ts

typescript
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';

@Module({
  imports: [
    // 启动日程管理系统
    ScheduleModule.forRoot(),
  ],
  // ...
})
export class AppModule {}
```就这样,你的应用现在已经具备了设置“智能闹钟”的能力。

### 2. 第二步:设置你的“闹钟” (使用装饰器)

`@nestjs/schedule` 提供了几种声明式的装饰器,让你可以在任何 `@Injectable()` 服务的方法上,轻松地设置定时任务。

#### **闹钟类型一:`@Cron()` - “精准的定时闹钟”**

这是最强大、最灵活的一种。它使用标准的 **Cron 表达式** 来定义复杂的执行时间规则。

#### **前置知识:什么是 Cron 表达式?**
Cron 表达式是一个由 5 个或 6 个字段组成的字符串,用来定义一个时间表。它的格式是:

┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ │ │ └─ Day of Week (0 - 7) (Sunday is 0 or 7) │ │ │ │ └─ Month (1 - 12) │ │ │ └─ Day of Month (1 - 31) │ │ └─ Hour (0 - 23) │ └─ Minute (0 - 59) └─ Second (0 - 59) (optional)```

  • * 代表“每一个”。
  • 45 * * * * * -> 每分钟的第 45 秒。
  • 0 10 * * * -> 每天上午 10:00 (省略了秒,等同于 0 0 10 * * *)。
  • 0 0 1 * * -> 每月 1 号的午夜。

代码示例:每天凌晨 4 点半生成报告

src/tasks/tasks.service.ts

typescript
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';

@Injectable()
export class TasksService {
  private readonly logger = new Logger(TasksService.name);

  // 使用 @Cron() 装饰器
  @Cron('30 4 * * *', { // Cron 表达式:每天 4:30 AM
    name: 'generateDailyReport', // 给任务起个名字
    timeZone: 'Asia/Shanghai',   // 指定时区
  })
  handleCron() {
    this.logger.debug('正在生成每日销售报告...');
    // 在这里执行生成报告的复杂逻辑...
    this.logger.debug('报告生成完毕!');
  }
}
```*   **`CronExpression` 枚举**: 为了方便,`@nestjs/schedule` 提供了一个 `CronExpression` 枚举,包含了一些常用的表达式,比如 `CronExpression.EVERY_30_SECONDS`。

---

#### **闹钟类型二:`@Interval()` - “重复的间隔闹钟”**

如果你不关心具体的“时刻”,只关心“每隔多久”执行一次,那么 `@Interval()` 更简单直观。

**代码示例:每 10 秒检查一次系统健康状态**

**`src/tasks/tasks.service.ts`**
```typescript
// ...接上面的代码
@Injectable()
export class TasksService {
  // ...

  @Interval('healthCheck', 20000) // 第一个参数是可选的任务名,第二个是间隔时间(毫秒)
  handleInterval() {
    this.logger.debug('正在执行系统健康检查...');
    // ...
  }
}

应用启动后,这个 handleInterval 方法会立即执行一次,然后每隔 20 秒重复执行。


闹钟类型三:@Timeout() - “一次性的延迟闹钟”

这个闹钟只会响一次。它会在应用启动后的指定延迟时间后,执行一次任务。

代码示例:应用启动 5 秒后,执行一次数据预热

src/tasks/tasks.service.ts

typescript
// ...接上面的代码
@Injectable()
export class TasksService {
  // ...

  @Timeout('dataWarmUp', 5000) // 第一个参数是可选的任务名,第二个是延迟时间(毫秒)
  handleTimeout() {
    this.logger.debug('正在执行一次性的数据预热任务...');
    // ...
  }
}

这个钩子对于执行那些需要在应用完全启动后,但又只需要执行一次的初始化任务非常有用。

3. “闹钟”的动态管理

有时候,我们不想在代码里写死定时任务,而是希望能够动态地创建、停止和管理它们。@nestjs/schedule 也提供了相应的服务。

我们可以注入 SchedulerRegistry 服务,它就像是所有闹钟的“总控制台”。

代码示例:动态添加和取消一个 Cron 任务

typescript
import { Injectable, Logger } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';

@Injectable()
export class DynamicTasksService {
  private readonly logger = new Logger(DynamicTasksService.name);

  constructor(private schedulerRegistry: SchedulerRegistry) {}

  // 动态添加一个任务
  addCronJob(name: string, seconds: number) {
    const job = new CronJob(`${seconds} * * * * *`, () => {
      this.logger.warn(`任务 ${name} 正在执行!(每分钟的第 ${seconds} 秒)`);
    });

    this.schedulerRegistry.addCronJob(name, job);
    job.start();

    this.logger.warn(`任务 ${name} 已添加!`);
  }

  // 动态删除一个任务
  deleteCron(name: string) {
    this.schedulerRegistry.deleteCronJob(name);
    this.logger.warn(`任务 ${name} 已删除!`);
  }
}
  • CronJob: 我们这里直接使用了底层的 cron 库的 CronJob 类来创建一个任务实例。
  • schedulerRegistry.addCronJob(name, job): 将这个任务实例注册到 NestJS 的调度器中,以便管理。

现在,你可以在你的 Controller 中注入 DynamicTasksService,然后通过 API 请求来动态地添加或删除定时任务了!

总结

@nestjs/schedule 为你的应用提供了一套强大、可靠且与 NestJS 生态完美融合的自动化任务调度方案。

当你想要...你应该使用...核心特点
在精确的时刻执行任务 (如每天午夜)@Cron()强大灵活,使用标准的 Cron 表达式。
按固定的时间间隔重复执行任务@Interval()简单直观,用于周期性轮询或检查。
在应用启动后延迟执行一次任务@Timeout()一次性,用于执行启动后的初始化脚本。
在运行时动态地控制任务注入 SchedulerRegistry完全的控制权,用于构建可配置的调度系统。

掌握了任务调度,你的 NestJS 应用就不再是一个只能被动响应的“服务员”,而升级成了一个能够主动思考、按时完成例行工作的“智能管家”,极大地提升了应用的自动化水平和能力边界。