好的,我们来探讨一个能让你的应用“活”起来,可以自动执行周期性任务的强大功能:任务调度 (Task Scheduling)。这就像是为你的应用设置了一系列精准的“智能闹钟”,让它在无人干预的情况下,也能按时完成各种预设的工作。
为你的应用设置“智能闹钟”:NestJS 任务调度完全指南
想象你的应用是一位勤勤恳恳的办公室文员。
他的日常工作除了处理即时到来的任务(响应 HTTP 请求)之外,还有很多需要在特定时间或按固定周期完成的例行公事:
- 每天午夜:生成前一天的销售报告。(
Cron Job
) - 每隔一小时:清理一次临时文件夹,删除过期文件。(
Interval
) - 在应用启动 5 分钟后:发送一封“系统已启动”的通知邮件。(
Timeout
)
如果每次都需要你手动登录服务器去触发这些操作,那简直是一场灾难。你需要一个全自动的“日程管理系统”,让他可以自己“看表”,到点就自动完成这些任务。
在 NestJS 中,这个“日程管理系统”就是由官方提供的 @nestjs/schedule
模块。它将著名的 node-cron
库与 NestJS 的依赖注入系统完美地结合在了一起。
1. 第一步:安装“日程管理系统” (@nestjs/schedule
)
第一步:安装必要的依赖
npm install @nestjs/schedule
第二步:在 AppModule
中注册 ScheduleModule
我们需要在根模块中,使用 ScheduleModule.forRoot()
来启动这个调度引擎。
src/app.module.ts
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
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
// ...接上面的代码
@Injectable()
export class TasksService {
// ...
@Timeout('dataWarmUp', 5000) // 第一个参数是可选的任务名,第二个是延迟时间(毫秒)
handleTimeout() {
this.logger.debug('正在执行一次性的数据预热任务...');
// ...
}
}
这个钩子对于执行那些需要在应用完全启动后,但又只需要执行一次的初始化任务非常有用。
3. “闹钟”的动态管理
有时候,我们不想在代码里写死定时任务,而是希望能够动态地创建、停止和管理它们。@nestjs/schedule
也提供了相应的服务。
我们可以注入 SchedulerRegistry
服务,它就像是所有闹钟的“总控制台”。
代码示例:动态添加和取消一个 Cron 任务
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 应用就不再是一个只能被动响应的“服务员”,而升级成了一个能够主动思考、按时完成例行工作的“智能管家”,极大地提升了应用的自动化水平和能力边界。