Fundamentals

生命周期事件

了解 Nest 应用程序和组件的生命周期管理,包括生命周期钩子的使用和应用程序关闭处理

生命周期事件

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 接口,如下所示:

@@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.`);
  }
}

异步初始化

OnModuleInitOnApplicationBootstrap 钩子都允许您延迟应用程序初始化过程(返回一个 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 的相关文档,了解更多关于 SIGINTSIGBREAK 和其他在 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() 钩子,因此如果有一些间隔、长时间运行的后台任务等,进程不会自动终止。