任务调度
任务调度允许您安排任意代码(方法/函数)在固定的日期/时间、重复的间隔或指定的间隔后执行一次。在 Linux 世界中,这通常由操作系统级别的 cron 等包处理。对于 Node.js 应用程序,有几个包可以模拟类似 cron 的功能。Nest 提供了 @nestjs/schedule 包,它与流行的 Node.js cron 包集成。我们将在本章中介绍这个包。
安装
要开始使用它,我们首先安装所需的依赖项。
要激活作业调度,将 ScheduleModule 导入到根 AppModule 中并运行 forRoot() 静态方法,如下所示:
.forRoot() 调用初始化调度程序并注册应用程序中存在的任何声明性 cron 作业、超时 和 间隔。注册发生在 onApplicationBootstrap 生命周期钩子发生时,确保所有模块都已加载并声明了任何计划的作业。
声明式 cron 任务
cron 作业安排任意函数(方法调用)自动运行。Cron 作业可以运行:
- 一次,在指定的日期/时间。
- 定期;定期作业可以在指定的时间间隔内的指定时刻运行(例如,每小时一次、每周一次、每 5 分钟一次)
通过在包含要执行的代码的方法定义之前使用 @Cron() 装饰器来声明 cron 作业,如下所示:
在这个例子中,handleCron() 方法将在当前秒为 45 时被调用。换句话说,该方法将每分钟运行一次,在 45 秒标记处。
@Cron() 装饰器支持以下标准 cron 模式:
- 星号(例如
*) - 范围(例如
1-3,5) - 步骤(例如
*/2)
在上面的例子中,我们向装饰器传递了 45 * * * * *。以下键显示了 cron 模式字符串中每个位置的解释:
一些示例 cron 模式:
@nestjs/schedule 包提供了一个方便的枚举,包含常用的 cron 模式。您可以如下使用此枚举:
在这个例子中,handleCron() 方法将每 30 秒被调用一次。如果发生异常,它将被记录到控制台,因为每个用 @Cron() 注释的方法都会自动包装在 try-catch 块中。
或者,您可以向 @Cron() 装饰器提供一个 JavaScript Date 对象。这样做会导致作业在指定的日期恰好执行一次。
使用 JavaScript 日期算术来安排相对于当前日期的作业。例如,@Cron(new Date(Date.now() + 10 * 1000)) 安排作业在应用程序启动后 10 秒运行。
此外,您可以提供其他选项作为 @Cron() 装饰器的第二个参数。
您可以在声明后访问和控制 cron 作业,或使用 动态 API 动态创建 cron 作业(其 cron 模式在运行时定义)。要通过 API 访问声明式 cron 作业,您必须通过在装饰器的第二个参数的可选选项对象中传递 name 属性来将作业与名称相关联。
声明式间隔任务
要声明一个方法应该在(重复的)指定间隔运行,请在方法定义前加上 @Interval() 装饰器。将间隔值(以毫秒为单位的数字)传递给装饰器,如下所示:
此机制在底层使用 JavaScript setInterval() 函数。您也可以利用 cron 作业来安排定期作业。
如果您想通过 动态 API 从声明类外部控制声明式间隔,请使用以下构造将间隔与名称相关联:
如果发生异常,它将被记录到控制台,因为每个用 @Interval() 注释的方法都会自动包装在 try-catch 块中。
动态 API 还支持创建动态间隔,其中间隔的属性在运行时定义,以及列出和删除它们。
声明式超时
要声明一个方法应该在指定的超时后(一次)运行,请在方法定义前加上 @Timeout() 装饰器。将相对时间偏移(以毫秒为单位)从应用程序启动传递给装饰器,如下所示:
此机制在底层使用 JavaScript setTimeout() 函数。
如果发生异常,它将被记录到控制台,因为每个用 @Timeout() 注释的方法都会自动包装在 try-catch 块中。
如果您想通过 动态 API 从声明类外部控制声明式超时,请使用以下构造将超时与名称相关联:
动态 API 还支持创建动态超时,其中超时的属性在运行时定义,以及列出和删除它们。
动态调度模块 API
@nestjs/schedule 模块提供了一个动态 API,用于管理声明式 cron 作业、超时 和 间隔。API 还支持创建和管理动态 cron 作业、超时和间隔,其中属性在运行时定义。
动态 cron 作业
使用 SchedulerRegistry API 从代码中的任何位置按名称获取对 CronJob 实例的引用。首先,使用标准构造函数注入来注入 SchedulerRegistry:
从 @nestjs/schedule 包中导入 SchedulerRegistry。
然后在类中如下使用它。假设使用以下声明创建了一个 cron 作业:
使用以下方法访问此作业:
getCronJob() 方法返回命名的 cron 作业。返回的 CronJob 对象具有以下方法:
stop()- 停止计划运行的作业。start()- 重新启动已停止的作业。setTime(time: CronTime)- 停止作业,为其设置新时间,然后启动它lastDate()- 返回作业上次执行的日期的DateTime表示。nextDate()- 返回作业下次执行计划的日期的DateTime表示。nextDates(count: number)- 提供DateTime表示的数组(大小为count),用于将触发作业执行的下一组日期。count默认为 0,返回空数组。
在 DateTime 对象上使用 toJSDate() 将它们呈现为与此 DateTime 等效的 JavaScript Date。
使用 SchedulerRegistry#addCronJob 方法动态创建新的 cron 作业,如下所示:
在这段代码中,我们使用 cron 包中的 CronJob 对象来创建 cron 作业。CronJob 构造函数的第一个参数是 cron 模式(就像 @Cron() 装饰器),第二个参数是当 cron 计时器触发时要执行的回调。SchedulerRegistry#addCronJob 方法接受两个参数:CronJob 的名称和 CronJob 对象本身。
记住在访问 SchedulerRegistry 之前注入它。从 cron 包导入 CronJob。
使用 SchedulerRegistry#deleteCronJob 方法删除命名的 cron 作业,如下所示:
使用 SchedulerRegistry#getCronJobs 方法列出所有 cron 作业,如下所示:
getCronJobs() 方法返回一个 map。在这段代码中,我们遍历 map 并尝试访问每个 CronJob 的 nextDate() 方法。在 CronJob API 中,如果作业已经触发并且没有未来的触发日期,它会抛出异常。
动态间隔
使用 SchedulerRegistry#getInterval 方法获取对间隔的引用。如上所述,使用标准构造函数注入来注入 SchedulerRegistry:
并如下使用它:
使用 SchedulerRegistry#addInterval 方法动态创建新的间隔,如下所示:
在这段代码中,我们创建一个标准的 JavaScript 间隔,然后将其传递给 SchedulerRegistry#addInterval 方法。
该方法接受两个参数:间隔的名称和间隔本身。
使用 SchedulerRegistry#deleteInterval 方法删除命名的间隔,如下所示:
使用 SchedulerRegistry#getIntervals 方法列出所有间隔,如下所示:
动态超时
使用 SchedulerRegistry#getTimeout 方法获取对超时的引用。如上所述,使用标准构造函数注入来注入 SchedulerRegistry:
并如下使用它:
使用 SchedulerRegistry#addTimeout 方法动态创建新的超时,如下所示:
在这段代码中,我们创建一个标准的 JavaScript 超时,然后将其传递给 SchedulerRegistry#addTimeout 方法。
该方法接受两个参数:超时的名称和超时本身。
使用 SchedulerRegistry#deleteTimeout 方法删除命名的超时,如下所示:
使用 SchedulerRegistry#getTimeouts 方法列出所有超时,如下所示:
示例
一个工作示例可在 这里 找到。

