[NestJS 带你飞!] DAY18 - Lifecycle Hooks

什麽是 Lifecycle Hook?

在开始介绍之前,先来了解一下何谓 生命周期 (Lifecycle),最简单的举例是人,人从出生到死亡就是一个完整的生命周期。那什麽是 生命周期钩子 (Lifecycle hook) ?即在生命周期中某个时间点会触发的事件,比如:小明在出生之後被赋予了国民身份、 5 岁的时候会上幼稚园等。在程序设计领域中,也有所谓的生命周期,最简单的分法为:开始到结束,有些框架甚至会设计 Lifecycle Hook 来针对不同时间点触发不同的事件,比如说:启动时先呼叫 API、关闭时留下 Log 资讯等。

Nest Lifecycle Hooks

Nest 也有设计 Lifecycle Hook,按照顺序排列共分成下方五个时间点:

  1. Module 初始化阶段 (onModuleInit)
  2. Nest App 启动阶段 (onApplicationBootstrap)
  3. Module 销毁阶段 (onModuleDestroy)
  4. Nest App 关闭前 (beforeApplicationShutdown)
  5. Nest App 关闭阶段 (onApplicationShutdown)

这里可以看出 Lifecycle Hooks 发生在「启动」与「关闭」这两个时间点,而它们可以在 modulescontrollersinjectables 被触发。需特别注意的是,在关闭时间点的 Hook 必须要在 bootstrap 执行时调用 app.enableShutdownHooks() 来开启此功能,会在执行 app.close() 或收到系统关闭讯号时 (Ctrl + C) 被触发。

注意:由於关闭时执行的 Hook 会消耗较多的效能在监听事件上,故预设是不启用的。

onModuleInit

onModuleInit 会在该模组的依赖项目处理完毕时被调用。假设 Nest App 有 AppModuleTodoModule,并在 AppModule 引入了 TodoModule
https://ithelp.ithome.com.tw/upload/images/20210522/20119338VHekXphWyY.png

AppModule 会先被载入,载入的时候会去读取它的依赖项目:TodoModuleAppControllerAppService,当这些依赖项目处理完毕後,也就是依赖项目会先呼叫 onModuleInitAppModule 才会调用其 onModuleInit,顺序如下图所示:
https://ithelp.ithome.com.tw/upload/images/20210522/201193384jhaImOilE.png

使用方式很简单,假如我们要在 AppModule 使用 onModuleInit,就让它实作 OnModuleInit 介面,并添加 onModuleInit 方法:

import { Module, OnModuleInit } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ]
})
export class AppModule implements OnModuleInit {
  onModuleInit(): void {
    console.log('[AppModule]: initial event!');
  }
}

如此一来,便会在初始化阶段於终端机显示下方字串:

[AppModule]: initial event!

onApplicationBootstrap

onApplicationBootstrap 在 Nest App 初始化所有模组後进行调用,会发生在连线建立前。与 onModuleInit 的执行顺序相同,会先执行依赖项目的 onApplicationBootstrap

假如我们要在 AppModule 使用 onApplicationBootstrap,就让它实作 OnApplicationBootstrap 介面,并添加 onApplicationBootstrap 方法:

import { Module, OnApplicationBootstrap } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ]
})
export class AppModule implements OnApplicationBootstrap {
  onApplicationBootstrap() {
    console.log('[AppModule]: bootstrap event!');
  }
}

如此一来,便会在启动後之阶段於终端机显示下方字串:

[AppModule]: bootstrap event!

onModuleDestroy

onModuleDestroy 在接收到系统关闭讯号或 app.close() 时调用。与 onModuleInit 的执行顺序 不同,会从 AppModule 的 Controller 与 Provider 开始执行 onModuleDestroy,执行完之後 AppModule 就会触发 onModuleDestroy,接着其依赖项目才会依序执行该 Hook,顺序如下图所示:
https://ithelp.ithome.com.tw/upload/images/20210522/201193387H40KuPQXA.png

注意:在 Nest 第 8 版中,onModuleDestroy 的执行顺序与 onModuleInit 相同,感谢热心的 mihuartuanr 提醒。

假如我们要在 AppModule 使用 onModuleDestroy,就让它实作 OnModuleDestroy 介面,并添加 onModuleDestroy 方法:

import { Module, OnModuleDestroy } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    TodoModule,
    UserModule
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ]
})
export class AppModule implements OnModuleDestroy {
  onModuleDestroy(): void {
    console.log('[AppModule]: destroy event!');
  }
}

如此一来,便会在关闭时於终端机显示下方字串:

[AppModule]: destroy event!

beforeApplicationShutdown

beforeApplicationShutdown 在 Nest App 关闭所有连线之前调用,并会触发 app.close()。与 onModuleInit 的执行顺序相同,会先执行依赖项目的 beforeApplicationShutdown

假如我们要在 AppModule 使用 beforeApplicationShutdown,就让它实作 BeforeApplicationShutdown 介面,并添加 beforeApplicationShutdown 方法:

import { BeforeApplicationShutdown, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ]
})
export class AppModule implements BeforeApplicationShutdown {
  beforeApplicationShutdown(): void {
    console.log('[AppModule]: before shutdown event!');
  }
}

如此一来,便会在关闭连线前之阶段於终端机显示下方字串:

[AppModule]: before shutdown event!

onApplicationShutdown

onApplicationShutdown 在 Nest App 关闭所有连接时进行调用。与 onModuleInit 的执行顺序相同,会先执行依赖项目的 onApplicationShutdown

假如我们要在 AppModule 使用 onApplicationShutdown,就让它实作 OnApplicationShutdown 介面,并添加 onApplicationShutdown 方法:

import { Module, OnApplicationShutdown } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ]
})
export class AppModule implements OnApplicationShutdown {
  onApplicationShutdown(): void {
    console.log('[AppModule]: shutdown event!');
  }
}

如此一来,便会在关闭时於终端机显示下方字串:

[AppModule]: shutdown event!

小结

运用 Lifecycle Hooks 可以有效地在适当时机点做适当的动作,以关闭时调用的 Hook 来说,通常会用在 Kubernetes 等服务上。这里附上今天的懒人包:

  1. Nest 的 Lifecycle Hooks 共有五个,主要是在「启动」与「关闭」这两个时间点触发。
  2. 五个 Hook 分别为:onModuleInitonApplicationBootstraponModuleDestroybeforeApplicationShutdownonApplicationShutdown
  3. 「关闭」时调用的 Hook 需要透过 app.enableShutdownHooks() 来启用此功能。

<<:  Day.25 提升大数据资料管理 - 资料表分区 ( MYSQL Partition)_2

>>:  实战操作 - 鸿海 2317

【Day 09】- 今天来创造 Ghost Process(基於断链隐藏 Process 的手法)

Agenda 资安宣言 测试环境与工具 学习目标 技术原理与程序码 References 下期预告 ...

[Day28] BERT(一)

一. 介绍 Bert全名为Bidirectional Encoder Representation ...

19 - Traces - 观察应用程序的效能瓶颈 (3/6) - 如何在 Kibana 使用 APM UI

Traces - 观察应用程序的效能瓶颈 系列文章 (1/6) - Elastic APM 基本介绍...

Day 05 - 想要够给力的机器-EC2

来到了中秋连假的第一天,买不到云上的月亮,我们就到云上买台机器来玩玩吧 1. 使用EC2好处? EC...

selenium爬虫:使用xpath

from selenium import webdriver import openpyxl imp...