任务调度¶
任务调度允许您安排任意代码(方法/函数)在固定的日期/时间、重复的间隔或在指定间隔后执行一次。
在 Linux 世界中,这通常是由像cron这样的包在操作系统级别上处理的。
对于 Node.js 应用程序,有几个包模拟了类似 cron 的功能。
Nest 提供了@nestjs/schedule
包,它集成了流行的 Node.js node-cron包。
我们将在本章中讨论这个包。
安装¶
要开始使用它,我们首先安装所需的依赖项。
要激活作业调度,请将ScheduleModule
导入到根模块AppModule
中,并运行forRoot()
静态方法,如下所示:
.forroot()
调用初始化调度器,并注册应用程序中存在的任何声明性cron job、timeout和interval。
当onApplicationBootstrap
生命周期钩子发生时,就会发生注册,以确保所有模块都已加载并声明了任何调度的作业。
声明式 cron jobs¶
cron 作业调度任意函数(方法调用)以自动运行。Cron 作业可以运行:
- 一次,在指定的日期/时间。
- 经常性地;循环作业可以在指定的时间间隔内(例如,每小时运行一次、每周运行一次、每 5 分钟运行一次)。
用@Cron()
装饰器在包含要执行的代码的方法定义之前声明一个 cron 作业,如下所示:
在这个例子中,handleCron()
方法将在当前秒为45
时被调用。
换句话说,该方法将在每分钟 45 秒时运行一次。
@Cron()
装饰器支持所有标准的cron 模式:
- 星号 (e.g.
*
) - 范围 (e.g.
1-3,5
) - 步频 (e.g.
*/2
)
在上面的例子中,我们将45 * * * * *
传递给装饰器。
下面的键显示了如何解释 cron 模式字符串中的每个位置:
* * * * * *
| | | | | |
| | | | | day of week
| | | | month
| | | day of month
| | hour
| minute
second (optional)
一些样本 cron 模式是:
* * * * * * |
每一秒 |
45 * * * * * |
每一分钟,45秒 |
0 10 * * * * |
每小时,第十分钟开始 |
0 */30 9-17 * * * |
早上9点到下午5点每隔30分钟一次 |
0 30 11 * * 1-5 |
星期一至五上午11时30分 |
@nestjs/schedule
包提供了一个方便的枚举,其中包含常用的 cron 模式。您可以按如下方式使用这个 enum:
在这个例子中,handleCron()
方法将每30
秒被调用一次。
或者,你可以为@Cron()
装饰器提供一个 JavaScript 的Date
对象。
这样做会导致作业在指定日期只执行一次。
!!! info 提示 使用 JavaScript 日期算法来安排相对于当前日期的作业。 例如,@Cron(new Date(Date.now() + 10 * 1000))
来调度一个作业在应用程序启动 10 秒后运行。
此外,你可以提供额外的选项作为@Cron()
装饰器的第二个参数。
name |
在声明cron作业之后,访问和控制cron作业很有用。 |
timeZone |
指定执行的时区。这将修改相对于您的时区的实际时间。如果时区无效,则抛出一个错误。您可以在[Moment Timezone](http://momentjs.com/timezone/)网站上查看所有可用的时区。 |
utcOffset |
这允许您指定时区的偏移量,而不是使用timezone 参数。
|
你可以在 cron 作业声明之后访问和控制它,或者使用Dynamic API动态创建一个 cron 作业(在运行时定义它的 cron 模式)。
要通过 API 访问一个声明性的 cron 作业,你必须将name
属性作为装饰器的第二个参数传递到一个可选的 options 对象中,从而将作业与一个名称关联起来。
声明式 interval¶
要声明一个方法应该以指定的(重复)时间间隔运行,请在方法定义前加上@Interval()
装饰器。
将 interval 值以毫秒为单位传递给装饰器,如下所示:
!!! info 提示 这个机制在底层使用了 JavaScript 的setInterval()
函数。您还可以利用 cron 作业来调度循环作业。
如果你想通过Dynamic API从外部控制你的声明性间隔,请使用以下构造将间隔与一个名称关联起来:
Dynamic API还支持 创建**动态间隔,其中间隔的属性在运行时定义,并**列出和删除 它们。
声明式 timeout¶
要声明一个方法应该在指定的超时时间运行(一次),请在方法定义前加上@Timeout()
装饰器。
将应用程序启动时的相对时间偏移(以毫秒为单位)传递给装饰器,如下所示:
!!! info 提示 这个机制在底层使用了 JavaScript 的setTimeout()
函数。
如果你想通过Dynamic API从外部控制你的声明性超时,请使用以下构造将超时与一个名称关联起来:
Dynamic API还支持 创建**动态超时,其中超时的属性在运行时定义,并**列出和删除 它们。
动态调度模块 API¶
@nestjs/schedule
模块提供了一个动态 API,支持管理声明式的cron jobs、timeout和interval。
该 API 还支持创建和管理 动态 cron jobs、timeout 和 interval,其中的属性是在运行时定义的。
动态 cron jobs¶
使用 SchedulerRegistry
API,从你的代码中任何地方获取一个CronJob
实例的名称引用。
首先,使用标准构造函数注入SchedulerRegistry
:
Hint
从@nestjs/schedule
包中导入SchedulerRegistry
。
然后像下面这样在类中使用它。假设一个 cron 作业是通过以下声明创建的:
使用以下方法访问此作业:
getCronJob()
方法返回指定的 cron 作业。返回的CronJob
对象有以下方法:
stop()
- 停止计划运行的作业。start()
- 重新启动已停止的作业。setTime(time: CronTime)
- 停止一个作业,为它设置一个新的时间,然后开始它lastDate()
- 返回作业最近执行日期的字符串表示形式nextDates(count: number)
- 返回一个表示即将到来的作业执行日期的moment
对象的数组(大小为count
)。
Hint
在moment
对象上使用toDate()
将其呈现为人类可读的形式。
使用SchedulerRegistry.addCronJob()
方法动态 创建 一个新的 cron job,如下所示:
在这段代码中,我们使用cron
包中的CronJob
对象来创建 cron 作业。
CronJob
构造函数的第一个参数是 cron 模式(就像 @Cron()
decorator),第二个参数是 cron 计时器触发时执行的回调。
SchedulerRegistry.addCronJob()
方法有两个参数:CronJob
的名称和CronJob
对象本身。
Warning
记得在访问之前注入SchedulerRegistry
。从cron
包中导入CronJob
。
使用SchedulerRegistry.deleteCronJob()
方法 删除 一个名为cron
的任务,如下所示:
使用SchedulerRegistry.getCronJobs()
方法 列出 所有cron
任务,如下所示:
getCronJobs()
方法返回一个map
。
在这段代码中,我们对映射进行迭代,并尝试访问每个CronJob
的nextDates()
方法。
在CronJob
API 中,如果一个任务已经被触发,并且没有未来的触发日期,它会抛出一个异常。
动态 intervals¶
Obtain a reference to an interval with the SchedulerRegistry.getInterval()
method. As above, inject SchedulerRegistry
using standard constructor injection:
And use it as follows:
Create a new interval dynamically using the SchedulerRegistry.addInterval()
method, as follows:
In this code, we create a standard JavaScript interval, then pass it to the ScheduleRegistry.addInterval()
method.
That method takes two arguments: a name for the interval, and the interval itself.
Delete a named interval using the SchedulerRegistry.deleteInterval()
method, as follows:
List all intervals using the SchedulerRegistry.getIntervals()
method as follows:
动态 timeouts¶
Obtain a reference to a timeout with the SchedulerRegistry.getTimeout()
method. As above, inject SchedulerRegistry
using standard constructor injection:
And use it as follows:
Create a new timeout dynamically using the SchedulerRegistry.addTimeout()
method, as follows:
In this code, we create a standard JavaScript timeout, then pass it to the ScheduleRegistry.addTimeout()
method.
That method takes two arguments: a name for the timeout, and the timeout itself.
Delete a named timeout using the SchedulerRegistry.deleteTimeout()
method, as follows:
List all timeouts using the SchedulerRegistry.getTimeouts()
method as follows:
例子¶
一个可用的例子在这里.