生命周期序列
下图描述了关键应用程序生命周期事件的序列,从应用程序启动到节点进程退出。我们可以将整个生命周期分为三个阶段:初始化、运行和终止。使用此生命周期,您可以规划模块和服务的适当初始化、管理活动连接,并在应用程序收到终止信号时正常关闭应用程序。
生命周期事件
生命周期事件发生在应用程序启动和关闭期间。 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)
// Starts listening for shutdown hooks
app.enableShutdownHooks()
await app.listen(3000)
}
bootstrap()
由于固有的平台限制,NestJS 对 Windows 上的应用程序关闭挂钩的支持有限。您可以预期 SIGINT
以及 SIGBREAK
和某种程度上的 SIGHUP
都可以工作 - 阅读更多。但是 SIGTERM
永远不会在 Windows 上工作,因为在任务管理器中终止进程是无条件的,即,应用程序无法检测或阻止它
。这里有一些来自 libuv 的 相关文档,可以了解有关如何在 Windows 上处理 SIGINT
、SIGBREAK
和其他内容的更多信息。另请参阅 Node.js 文档中的 进程信号事件
enableShutdownHooks
通过启动侦听器来消耗内存。如果您在单个 Node 进程中运行多个 Nest 应用(例如,使用 Jest 运行并行测试时),Node 可能会抱怨侦听器进程过多。因此,默认情况下不启用 enableShutdownHooks
。当您在单个 Node 进程中运行多个实例时,请注意这种情况。
当应用程序收到终止信号时,它将调用任何已注册的 onModuleDestroy()
、beforeApplicationShutdown()
,然后 onApplicationShutdown()
方法(按上述顺序),并将相应的信号作为第一个参数。如果注册的函数等待异步调用(返回承诺),则 Nest 将不会继续执行该序列,直到承诺被解决或被拒绝。
@Injectable()
class UsersService implements OnApplicationShutdown {
onApplicationShutdown(signal: string) {
console.log(signal) // e.g. "SIGINT"
}
}
调用 app.close()
不会终止 Node 进程,而只会触发 onModuleDestroy()
和 onApplicationShutdown()
钩子,因此如果存在某些间隔、长时间运行的后台任务等,进程不会自动终止。