生命周期事件
Nest应用程序以及每个应用程序元素都由Nest管理的生命周期。 Nest提供了生命周期钩子,可以在关键的生命周期事件发生时提供可见性, 并在这些事件发生时执行注册的代码(在模块、提供程序或控制器上运行)。
生命周期序列
以下图表描述了关键应用程序生命周期事件的序列,从应用程序启动到节点进程退出的过程。 我们可以将整个生命周期分为三个阶段:初始化、运行和终止。 利用这个生命周期,您可以计划模块和服务的适当初始化,管理活动连接, 并在接收到终止信号时优雅地关闭您的应用程序。
生命周期事件#
生命周期事件发生在应用程序启动和关闭期间。 Nest在每个以下生命周期事件上调用模块、提供程序和控制器上注册的生命周期钩子方法(首先需要启用关闭钩子,如下所述)。 如上图所示,Nest还调用适当的底层方法来开始监听连接和停止监听连接。
在以下表格中,只有在显式调用app.close()
或进程接收到特殊的系统信号
(例如SIGTERM)且您在应用程序启动时正确调用了enableShutdownHooks
(见下文的应用程序关闭部分)时,才会触发onModuleDestroy
、
beforeApplicationShutdown
和onApplicationShutdown
。
生命周期钩子方法 | 触发钩子方法调用的生命周期事件 |
---|---|
onModuleInit() | 在主模块的依赖项已解析后调用一次。 |
onApplicationBootstrap() | 在所有模块初始化 完成后调用,但在开始监听连接之前。 |
onModuleDestroy()* | 在接收到终止信号(例如,SIGTERM )后调用。 |
beforeApplicationShutdown()* | 在所有onModuleDestroy() 处理程序完成后调用(Promises已解析或拒绝);一旦完成(Promises已解析或拒绝),将关闭所有现有连接(调用app.close() )。 |
onApplicationShutdown()* | 在连接关闭后调用(app.close() 解析完成)。 |
- 对于这些事件,如果您没有显式调用
app.close()
,则必须选择让它们与SIGTERM
等系统信号一起使用。 请参阅下面的应用程序关闭
上述列出的生命周期钩子对于请求范围的类不会触发。请求范围的类与应用程序生命周期无关,其生命周期是不可预测的。 它们专门为每个请求创建,并在响应发送后自动进行垃圾回收。
onModuleInit()
和onApplicationBootstrap()
的执行顺序直接取决于模块导入的顺序,等待前一个钩子。
使用
每个生命周期钩子都由一个接口表示。
接口在技术上是可选的,因为它们在TypeScript编译后不存在。
尽管如此,最好的实践是使用它们以便从强类型和编辑器工具中受益。
要注册生命周期钩子,请实现适当的接口。
例如,要在特定类(例如Controller
、Provider
或Module
)上注册在模块初始化期间调用的方法,
实现OnModuleInit
接口,并提供一个onModuleInit()
方法,
如下所示:
import { Injectable, OnModuleInit } from '@nestjs/common';
@Injectable()
export class UsersService implements OnModuleInit {
onModuleInit() {
console.log(`The module has been initialized.`);
}
}
异步初始化
OnModuleInit
和OnApplicationBootstrap
钩子都允许您推迟应用程序初始化过程
(返回一个Promise
或将方法标记为async
并在方法体内await
异步方法的完成)。
async onModuleInit(): Promise<void> {
await this.fetch();
}
应用程序关闭
onModuleDestroy()
、beforeApplicationShutdown()
和onApplicationShutdown()
钩子
在终止阶段被调用(响应显式调用app.close()
或者接收到系统信号如SIGTERM时,如果选择接收的话)。
这个特性经常与Kubernetes一起使用,用于管理容器的生命周期,或者在Heroku中用于dynos或类似的服务。
关闭钩子监听器会消耗系统资源,因此它们默认是禁用的。
要使用关闭钩子,必须通过调用enableShutdownHooks()
来启用监听器:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 启动监听关闭钩子
app.enableShutdownHooks();
await app.listen(3000);
}
bootstrap();
由于固有的平台限制,NestJS在Windows上对应用程序关闭钩子的支持有限。
可以期望SIGINT
工作,以及SIGBREAK
并在某种程度上SIGHUP
- 阅读更多。
然而,SIGTERM
在Windows上永远不会工作,因为在任务管理器中终止进程是无条件的,“即,应用程序无法检测或阻止它”。
这里有一些来自libuv的相关文档,了解有关在Windows上如何处理SIGINT
、SIGBREAK
等的更多信息。
此外,请查看Node.js关于进程信号事件的文档。
enableShutdownHooks
通过启动监听器消耗内存。
在运行多个Nest应用程序的单个Node进程中(例如,在Jest中运行并行测试时),Node可能会抱怨有过多的监听器进程。
因此,默认情况下不启用enableShutdownHooks
。在运行多个实例的单个Node进程中时,请注意此条件。
当应用程序接收到终止信号时,它将调用任何已注册的onModuleDestroy()
、beforeApplicationShutdown()
,
然后调用onApplicationShutdown()
方法(如上述顺序),并将相应的信号作为第一个参数。
如果已注册的函数等待异步调用(返回一个promise),Nest将在promise解析或拒绝之前不会继续顺序。
@Injectable()
class UsersService implements OnApplicationShutdown {
onApplicationShutdown(signal: string) {
console.log(signal); // 例如 "SIGINT"
}
}
调用app.close()
不会终止Node进程,而只会触发onModuleDestroy()
和onApplicationShutdown()
钩子,
因此如果有一些间隔、长时间运行的后台任务等,进程不会被自动终止。