Nest.js의 LifeCycle(생명 주기)는 어떻게 되지?

Nest.js의 LifeCycle(생명 주기)는 어떻게 되지?

Tag
NestJS

생명 주기 이벤트

React, Flutter와 같이 NestJS에서도 수명 주기라는 것이 존재한다.
 
관련하여 Nest에서는 두가지 기능을 제공한다.
  • 주요 생명 주기 이벤트에 대한 가시성을 제공 하는 수명 주기 후크
  • 이벤트가 발생할 때 조치를 취할 수 있는 기능
 

라이프사이클 시퀀스

앱이 부트스트랩 되어, 프로세스가 종료될 때 까지의 다이어그램을 보자.
notion image
순서는 아래와 같이 간단하게 3가지로 정리할 수 있다.
  1. 초기화
  1. 실행
  1. 종료
 
수명 주기 후크 방법
후크 메서드 호출을 트리거하는 수명 주기 이벤트
onModuleInit()
호스트 모듈의 종속성이 해결되면 호출
onApplicationBootstrap()
모든 모듈이 초기화된 후 연결을 수신 대기하기 전에 호출
onModuleDestroy()*
종료 신호(예: SIGTERM)가 수신된 후 호출
beforeApplicationShutdown()*
모든 onModuleDestroy()처리기가 완료된 후 호출 ( Promise 해결 또는 거부 ) 완료되면(Promise가 해결되거나 거부됨) 모든 기존 연결이 닫힘 ( app.close()호출 )
onApplicationShutdown()*
연결 종료 후 호출 ( app.close()해결 )
* 로 표시한 후크의 경우 명시적으로 호출하지 않는다면, enableShutdownHooks() 를 호출해주어야 한다.
이 수명 주기를 사용하여 모듈 및 서비스의 적절한 초기화를 계획하고, 활성 연결을 관리하고, 종료 신호를 받으면 애플리케이션을 정상적으로 종료할 수 있다.
 

사용은 어떻게 하는가?

인터페이스를 이용한다.
인터페이스 같은 경우 당연하게도 Typescript 문법이기에, 컴파일이 되면 사라지게 된다. 그러므로 선택 사항이지만 당연히도 쓰는게 좋을 것이다. ( vscode의 도움을 받으려면.. )
당연히도 async, await 표현을 통해 비동기적으로 초기화 또한 가능하다.

onModuleInit()

import { Injectable, OnModuleInit } from '@nestjs/common'; @Injectable() export class UsersService implements OnModuleInit { // sync onModuleInit() { console.log(`The module has been initialized.`); } // async async onMoudleInit(): Promise<void> { await this.fetch(); } async fetch(): Promise<void> { await db.getData(); // example } }
 

앱 종료

onModuleDestroy(), beforeApplicationShutdown() 의 경우 종료 단계에서 호출된다.
onApplicationShutdown 의 경우 시스템 신호에 대해 응답을 하게 되는데, 보통 k8s 와 함께 사용된다고 한다.
 
종료 후크를 사용하려면 그에 대한 리스너를 활성화 해야하는데, 이는 enableShutdownHooks() 를 호출하면 된다.
bootstrap() 시 내부에서 shutdown에 대한 리스너를 달고 있다고 생각하면 되겠다.
 
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // shutdown hooks에 대한 리스닝. 이 후크를 무조건 먼저 활성화 해야함 app.enableShutdownHooks(); await app.listen(3000); } bootstrap();
 
종료하라는 신호를 받게 되면, onModuleDestroy(), beforeApplicationShutdown(), onApplicationShutdown() 메서드를 호출하게 되는데, 첫 번째 매개 변수로 해당 신호를 받는다.
등록된 함수들이 async인 경우, Nest는 resolve / reject 될 때까지 기다리게 된다.
 
@Injectable() class UsersService implements OnApplicationShutdown { onApplicationShutdown(signal: string) { console.log(signal); // e.g. "SIGINT" } }

로직 수행의 흐름

notion image
  1. Request
  1. middleware ( 미들웨어 )
  1. guards ( 가드 )
      • 주로 permission ( 인증 ) 처리를 할 때 사용
  1. pre-interceptors ( 인터셉터 )
      • 주로 post-interceptor를 위한 변수 선언, 함수 실행 ( optional )
  1. Pipes ( 파이프 )
      • 변환( 요청 바디를 원하는 형식으로 변환 ), 유효성 검사
  1. Controller ( 컨트롤러 )
      • 라우터 역할을 수행
  1. Service ( 서비스 )
      • 해당 요청에 대한 핵심 로직이 수행
  1. post-interceptor ( 인터셉터 )
      • 주로 pre-interceptor 로직을 가지고 응답한 데이터를 가공하거나 전체 로직의 속도 측정. 최종적으로 성공적인 응답 데이터를 보냄
  1. exception filters ( 필터 )
      • 예외 처리를 담당. 에러 메세지를 원하는 형태로 가공해서 응답
  1. Response

References