Skip to main content

生命周期事件

Nest应用程序以及每个应用程序元素都由Nest管理的生命周期。 Nest提供了生命周期钩子,可以在关键的生命周期事件发生时提供可见性, 并在这些事件发生时执行注册的代码(在模块、提供程序或控制器上运行)。

生命周期序列

以下图表描述了关键应用程序生命周期事件的序列,从应用程序启动到节点进程退出的过程。 我们可以将整个生命周期分为三个阶段:初始化、运行和终止。 利用这个生命周期,您可以计划模块和服务的适当初始化,管理活动连接, 并在接收到终止信号时优雅地关闭您的应用程序。

生命周期事件#

生命周期事件发生在应用程序启动和关闭期间。 Nest在每个以下生命周期事件上调用模块、提供程序和控制器上注册的生命周期钩子方法(首先需要启用关闭钩子,如下所述)。 如上图所示,Nest还调用适当的底层方法来开始监听连接和停止监听连接。

在以下表格中,只有在显式调用app.close()或进程接收到特殊的系统信号 (例如SIGTERM)且您在应用程序启动时正确调用了enableShutdownHooks (见下文的应用程序关闭部分)时,才会触发onModuleDestroybeforeApplicationShutdownonApplicationShutdown

生命周期钩子方法触发钩子方法调用的生命周期事件
onModuleInit()在主模块的依赖项已解析后调用一次。
onApplicationBootstrap()在所有模块初始化完成后调用,但在开始监听连接之前。
onModuleDestroy()*在接收到终止信号(例如,SIGTERM)后调用。
beforeApplicationShutdown()*在所有onModuleDestroy()处理程序完成后调用(Promises已解析或拒绝);一旦完成(Promises已解析或拒绝),将关闭所有现有连接(调用app.close())。
onApplicationShutdown()*在连接关闭后调用(app.close()解析完成)。
  • 对于这些事件,如果您没有显式调用app.close(),则必须选择让它们与SIGTERM等系统信号一起使用。 请参阅下面的应用程序关闭
warning

上述列出的生命周期钩子对于请求范围的类不会触发。请求范围的类与应用程序生命周期无关,其生命周期是不可预测的。 它们专门为每个请求创建,并在响应发送后自动进行垃圾回收。

tip

onModuleInit()onApplicationBootstrap()的执行顺序直接取决于模块导入的顺序,等待前一个钩子。

使用

每个生命周期钩子都由一个接口表示。 接口在技术上是可选的,因为它们在TypeScript编译后不存在。 尽管如此,最好的实践是使用它们以便从强类型和编辑器工具中受益。 要注册生命周期钩子,请实现适当的接口。 例如,要在特定类(例如ControllerProviderModule)上注册在模块初始化期间调用的方法, 实现OnModuleInit接口,并提供一个onModuleInit()方法, 如下所示:

import { Injectable, OnModuleInit } from '@nestjs/common';

@Injectable()
export class UsersService implements OnModuleInit {
onModuleInit() {
console.log(`The module has been initialized.`);
}
}

异步初始化

OnModuleInitOnApplicationBootstrap钩子都允许您推迟应用程序初始化过程 (返回一个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();
warning

由于固有的平台限制,NestJS在Windows上对应用程序关闭钩子的支持有限。 可以期望SIGINT工作,以及SIGBREAK并在某种程度上SIGHUP - 阅读更多。 然而,SIGTERM在Windows上永远不会工作,因为在任务管理器中终止进程是无条件的,“即,应用程序无法检测或阻止它”。 这里有一些来自libuv的相关文档,了解有关在Windows上如何处理SIGINTSIGBREAK等的更多信息。 此外,请查看Node.js关于进程信号事件的文档。

info

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"
}
}
info

调用app.close()不会终止Node进程,而只会触发onModuleDestroy()onApplicationShutdown()钩子, 因此如果有一些间隔、长时间运行的后台任务等,进程不会被自动终止。