Skip to content

生命周期事件

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

生命周期顺序

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

生命周期事件

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

在下表中,onModuleInitonApplicationBootstrap 仅在你显式调用 app.init()app.listen() 时才会触发。

在下表中,onModuleDestroybeforeApplicationShutdownonApplicationShutdown 仅在你显式调用 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() 方法,如下所示:

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

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

异步初始化

OnModuleInitOnApplicationBootstrap 钩子都允许你延迟应用程序初始化过程(返回一个 Promise 或将方法标记为 async 并在方法体中 await 异步方法的完成)。

typescript
async onModuleInit(): Promise<void> {
  await this.fetch();
}

应用程序关闭

onModuleDestroy()beforeApplicationShutdown()onApplicationShutdown() 钩子在终止阶段被调用(响应对 app.close() 的显式调用,或在选择启用后收到系统信号如 SIGTERM 时)。此功能通常与 Kubernetes 一起用于管理容器的生命周期,或被 Heroku 用于 dynos 或类似服务。

关闭钩子监听器会消耗系统资源,因此默认情况下是禁用的。要使用关闭钩子,你必须通过调用 enableShutdownHooks() 来启用监听器

typescript
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 的相关文档可以了解更多关于 SIGINTSIGBREAK 和其他信号在 Windows 上的处理方式。另请参阅 Node.js 的 Process Signal Events 文档。

信息

enableShutdownHooks 通过启动监听器来消耗内存。在你在单个 Node 进程中运行多个 Nest 应用的情况下(例如,使用 Jest 运行并行测试时),Node 可能会抱怨监听器进程过多。因此,enableShutdownHooks 默认未启用。在单个 Node 进程中运行多个实例时请注意这一点。

当应用程序收到终止信号时,它将调用所有注册的 onModuleDestroy()beforeApplicationShutdown(),然后是 onApplicationShutdown() 方法(按上述顺序),并将相应的信号作为第一个参数传入。如果注册的函数等待异步调用(返回 Promise),Nest 将不会继续执行序列,直到该 Promise 被解决或拒绝。

typescript
@Injectable()
class UsersService implements OnApplicationShutdown {
  onApplicationShutdown(signal: string) {
    console.log(signal); // 例如 "SIGINT"
  }
}

信息

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

基于 NestJS 官方文档翻译