生命周期事件
生命周期事件
Nest 应用程序以及每个应用程序元素都有一个由 Nest 管理的生命周期。Nest 提供了生命周期钩子,让您能够洞察关键的生命周期事件,并在这些事件发生时采取行动(在您的模块、提供者或控制器上运行注册的代码)。
生命周期序列
下图描述了关键应用程序生命周期事件的序列,从应用程序启动到 node 进程退出的整个过程。我们可以将整个生命周期分为三个阶段:初始化、运行和终止。使用这个生命周期,您可以规划模块和服务的适当初始化,管理活动连接,并在应用程序收到终止信号时优雅地关闭您的应用程序。

生命周期事件
生命周期事件在应用程序启动和关闭期间发生。Nest 在以下每个生命周期事件中调用模块、提供者和控制器上注册的生命周期钩子方法(关闭钩子需要首先启用,如下文所述)。如上图所示,Nest 还会调用适当的底层方法来开始监听连接和停止监听连接。
在下表中,onModuleInit 和 onApplicationBootstrap 只有在您显式调用 app.init() 或 app.listen() 时才会触发。
在下表中,onModuleDestroy、beforeApplicationShutdown 和 onApplicationShutdown 只有在您显式调用 app.close() 或进程收到特殊系统信号(如 SIGTERM)并且您在应用程序启动时正确调用了 enableShutdownHooks 时才会触发(请参见下面的应用程序关闭部分)。
| 生命周期钩子方法 | 触发钩子方法调用的生命周期事件 |
|---|---|
onModuleInit() | 在主机模块的依赖项已解析后调用一次。 |
onApplicationBootstrap() | 在所有模块初始化后但在监听连接之前调用一次。 |
onModuleDestroy()* | 在收到终止信号(例如 SIGTERM)后调用。 |
beforeApplicationShutdown()* | 在所有 onModuleDestroy() 处理程序完成后调用(Promise 已解决或拒绝);完成后(Promise 已解决或拒绝),所有现有连接将被关闭(调用 app.close())。 |
onApplicationShutdown()* | 在连接关闭后调用(app.close() 解决)。 |
* 对于这些事件,如果您没有显式调用 app.close(),您必须选择加入以使它们与系统信号(如 SIGTERM)一起工作。请参见下面的应用程序关闭。
警告 上面列出的生命周期钩子不会为请求作用域类触发。请求作用域类不与应用程序生命周期绑定,它们的生命周期是不可预测的。它们专门为每个请求创建,并在响应发送后自动垃圾回收。
提示 onModuleInit() 和 onApplicationBootstrap() 的执行顺序直接取决于模块导入的顺序,等待前一个钩子。
用法
每个生命周期钩子都由一个接口表示。接口在技术上是可选的,因为它们在 TypeScript 编译后不存在。尽管如此,使用它们是一个好的做法,以便从强类型和编辑器工具中受益。要注册生命周期钩子,请实现适当的接口。例如,要注册一个在特定类(例如,控制器、提供者或模块)的模块初始化期间调用的方法,请通过提供 onModuleInit() 方法来实现 OnModuleInit 接口,如下所示:
@@filename()
import { Injectable, OnModuleInit } from '@nestjs/common';
@Injectable()
export class UsersService implements OnModuleInit {
onModuleInit() {
console.log(`The module has been initialized.`);
}
}
@@switch
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
onModuleInit() {
console.log(`The module has been initialized.`);
}
}
异步初始化
OnModuleInit 和 OnApplicationBootstrap 钩子都允许您延迟应用程序初始化过程(返回一个 Promise 或将方法标记为 async 并在方法体中 await 异步方法完成)。
@@filename()
async onModuleInit(): Promise<void> {
await this.fetch();
}
@@switch
async onModuleInit() {
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(process.env.PORT ?? 3000);
}
bootstrap();
警告 由于固有的平台限制,NestJS 在 Windows 上对应用程序关闭钩子的支持有限。您可以期望 SIGINT 能够工作,以及 SIGBREAK 和在某种程度上 SIGHUP - 阅读更多。但是 SIGTERM 在 Windows 上永远不会工作,因为在任务管理器中杀死进程是无条件的,"即,应用程序无法检测或阻止它"。这里有一些来自 libuv 的相关文档,了解更多关于 SIGINT、SIGBREAK 和其他在 Windows 上如何处理的信息。另外,请参见 Node.js 的进程信号事件文档。
信息 enableShutdownHooks 通过启动监听器来消耗内存。在您在单个 Node 进程中运行多个 Nest 应用程序的情况下(例如,使用 Jest 运行并行测试时),Node 可能会抱怨过多的监听器进程。因此,enableShutdownHooks 默认情况下不启用。当您在单个 Node 进程中运行多个实例时,请注意这种情况。
当应用程序收到终止信号时,它将调用任何注册的 onModuleDestroy()、beforeApplicationShutdown(),然后调用 onApplicationShutdown() 方法(按照上述描述的顺序),并将相应的信号作为第一个参数。如果注册的函数等待异步调用(返回一个 promise),Nest 将不会继续序列,直到 promise 被解决或拒绝。
@@filename()
@Injectable()
class UsersService implements OnApplicationShutdown {
onApplicationShutdown(signal: string) {
console.log(signal); // 例如 "SIGINT"
}
}
@@switch
@Injectable()
class UsersService implements OnApplicationShutdown {
onApplicationShutdown(signal) {
console.log(signal); // 例如 "SIGINT"
}
}
信息 调用 app.close() 不会终止 Node 进程,而只会触发 onModuleDestroy() 和 onApplicationShutdown() 钩子,因此如果有一些间隔、长时间运行的后台任务等,进程不会自动终止。