[Nest.JS] 애플리케이션 라이프사이클

궁금하면 500원·2024년 8월 8일
0

NestJS의 애플리케이션 라이프사이클은 애플리케이션의 시작, 초기화, 실행, 종료에
이르는 과정을 관리하는 구조입니다.

NestJS는 모듈, 프로바이더, 컨트롤러 간의 의존성 주입을 관리하고, 필요한 경우 특정 단계에서 필요한 로직을 실행하도록 다양한 라이프사이클 후크를 제공합니다.

이 구조를 이해하면 애플리케이션의 상태를 효과적으로 제어하고,
특정 단계에서 로직을 실행할 수 있습니다.

NestJS 라이프사이클의 주요 흐름은 다음과 같습니다

1. 애플리케이션 시작 및 초기화

NestJS 애플리케이션은 부트스트랩 과정에서 여러 단계를 거칩니다.

  • NestFactory.create(): 애플리케이션 인스턴스를 생성하는 과정입니다.
    이 과정에서 애플리케이션의 루트 모듈이 초기화되고, 필요한 모든 모듈, 서비스, 컨트롤러 등이 설정됩니다.

  • 의존성 주입 (Dependency Injection): 각 모듈에 정의된 프로바이더와 서비스가 NestJS의 DI 컨테이너에 의해 주입됩니다.
    이를 통해 필요한 인스턴스들이 자동으로 연결됩니다.

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

2. 모듈 초기화

NestJS의 핵심 구조는 모듈입니다.

각 모듈이 초기화되는 과정에서 의존성 주입, 프로바이더 등록,
그리고 컨트롤러 연결이 이루어집니다.

모듈의 초기화 순서:

1. 루트 모듈이 먼저 초기화됩니다.

2. 하위 모듈이 그다음에 초기화되며, 각 모듈에서 정의된 프로바이더와 컨트롤러가 등록됩니다.

  • 라이프사이클 후크: 모듈이 초기화되거나 종료될 때 특정 로직을 실행하고 싶다면 라이프사이클 후크(Lifecycle Hook)를 사용할 수 있습니다.

3. 라이프사이클 후크 (Lifecycle Hooks)

NestJS는 5가지 주요 라이프사이클 후크를 제공합니다.
이 후크들을 사용하면 각 단계에서 필요한 동작을 제어할 수 있습니다.

1) onModuleInit()

  • 모듈이 초기화된 후 호출됩니다.

  • 서비스나 프로바이더에서 이 메서드를 구현하면,
    해당 클래스가 모든 의존성을 주입받은 후 실행됩니다.

@Injectable()
export class UserService implements OnModuleInit {
  onModuleInit() {
    console.log('UserService has been initialized');
  }
}

2) onModuleDestroy()

  • 모듈이 종료될 때 호출됩니다.
  • 애플리케이션이 종료될 때 자원을 해제하거나 특정 종료 처리를 할 때 사용할 수 있습니다.
@Injectable()
export class UserService implements OnModuleDestroy {
  onModuleDestroy() {
    console.log('UserService has been destroyed');
  }
}

3) beforeApplicationShutdown()

  • 애플리케이션이 종료되기 직전에 실행됩니다.
  • 이를 통해 데이터베이스 연결 종료, 파일 저장 등 종료 전 필요한 작업을 수행할 수 있습니다.
@Injectable()
export class UserService implements BeforeApplicationShutdown {
  beforeApplicationShutdown(signal?: string) {
    console.log('App is about to shut down', signal);
  }
}

4) onApplicationBootstrap()

  • 애플리케이션이 부트스트랩 과정을 마치고, 모든 모듈과 서비스가 완전히 초기화된 후 호출됩니다.
  • 애플리케이션이 완전히 준비된 후 특정 초기화 작업을 실행할 때 유용합니다.
@Injectable()
export class AppService implements OnApplicationBootstrap {
  onApplicationBootstrap() {
    console.log('Application has bootstrapped');
  }
}

5) afterApplicationShutdown()

  • 애플리케이션이 완전히 종료된 후 호출됩니다.
  • 자원 정리 작업을 마무리하거나 종료 후 작업을 수행할 때 사용합니다.
@Injectable()
export class AppService implements AfterApplicationShutdown {
  afterApplicationShutdown() {
    console.log('Application has shut down');
  }
}

4. 의존성 주입과 프로바이더의 라이프사이클

NestJS에서 의존성 주입 (DI)은 애플리케이션의 핵심 요소입니다.

각 프로바이더는 생성될 때 라이프사이클을 따르며,
NestJS의 DI 컨테이너에 의해 관리됩니다.

  • 프로바이더는 모듈의 providers 배열에 정의되고, 애플리케이션에서 필요할 때마다 생성되고 주입됩니다.

  • 프로바이더의 생성 과정에서 onModuleInit, onApplicationBootstrap과 같은 후크를 통해 초기화 작업을 수행할 수 있습니다.

@Module({
  providers: [UserService],
})
export class UserModule {}

5. 애플리케이션 종료

NestJS 애플리케이션이 종료될 때 Graceful Shutdown을 지원하여, 종료 시 실행 중인 요청을 처리하고 안전하게 애플리케이션을 종료할 수 있습니다.

  • 애플리케이션이 종료될 때, beforeApplicationShutdown 및 onModuleDestroy 후크를 통해 종료 작업을 관리합니다.

  • 종료 신호(SIGINT, SIGTERM 등)를 받을 때 애플리케이션이 즉시 중지되지 않고, 현재 진행 중인 작업을 완료한 후 종료됩니다.

6. Request Lifecycle

NestJS에서 HTTP 요청이 들어오면, 요청에 대한 처리가 다음과 같은 단계를 거칩니다

- 미들웨어: 요청이 들어오면 먼저 미들웨어를 통해 필터링 또는 전처리 작업을 합니다.
- 가드 (Guards): 요청을 보호할 필요가 있을 때 가드를 사용하여 인증이나 권한을 검사합니다.
- 인터셉터 (Interceptors): 요청 및 응답을 가로채서 로깅, 캐싱 등의 작업을 수행할 수 있습니다.
- 파이프 (Pipes): 요청 데이터를 유효성 검사하거나 변환할 때 사용합니다.
- 컨트롤러: 요청이 컨트롤러에 전달되어 비즈니스 로직을 실행합니다.
- 필터 (Filters): 요청 처리 중 발생한 예외를 처리합니다.

정리

NestJS 라이프사이클은 애플리케이션 시작, 모듈 초기화, 서비스 로딩, 요청 처리, 종료 등
각 단계에서 명확한 제어를 가능하게 하는 구조로 설계되어 있습니다.

이를 통해 애플리케이션의 상태에 맞는 적절한 작업을 수행할 수 있으며,
여러 후크를 통해 다양한 시점에서 원하는 작업을 추가로 처리할 수 있습니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글