NestJS는 lifecycle hook을 제공합니다 — 애플리케이션이나 provider의 생명주기(초기화와 종료)의 특정 순간에 코드를 실행하기 위해 구현하는 메서드입니다. 이들은 설정(리소스 연결)과 정리(연결을 우아하게 닫기)에 필수적입니다.
주요 hook
()
, {
() {
.();
}
() {
.();
}
}
초기화 (시작):
onModuleInit() → module의 provider가 초기화된 후
onApplicationBootstrap()→ 모든 module이 초기화된 후 (전체 앱 준비됨)
종료 (우아한 종료):
onModuleDestroy() → module이 파괴될 때 정리
beforeApplicationShutdown() → 종료 완료 전
onApplicationShutdown(signal) → 최종 종료 (signal = SIGTERM 등)
@Injectable()
export class PrismaService extends PrismaClient
implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
await this.$connect(); // 시작 시 연결
}
async onModuleDestroy() {
await this.$disconnect(); // 종료 시 연결 해제 — 깔끔한 해제
}
}
이는 명시적 설정/해제가 필요한 리소스의 표준 패턴입니다 — onModuleInit에서 연결, onModuleDestroy에서 해제.
// shutdown hook은 명시적으로 활성화해야 함
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks(); // ❗ onApplicationShutdown 등이 발동되려면 필수
Shutdown hook은 enableShutdownHooks()를 호출해야만 실행됩니다 — 잊기 쉬우며, 그러면 정리가 절대 일어나지 않습니다.
앱이 SIGTERM(배포, 스케일 다운, 컨테이너 중지)을 받을 때:
✗ shutdown hook 없이 → 연결이 열린 채로 남고, 진행 중인 작업이 버려짐
✓ shutdown hook과 함께 → DB/Redis/queue를 깔끔하게 닫고, 작업을 마침 → 무중단
Lifecycle hook은 NestJS 애플리케이션에서 리소스를 올바르게 관리하는 데 중요합니다 — 초기화(데이터베이스/Redis 연결 열기, 데이터 로드, service 등록)와, 결정적으로 종료 시 우아한 정리(연결 닫기, 버퍼 플러시, 진행 중인 작업 마침)를 수행하는 적절한 위치를 제공합니다.
이를 이해하는 것은 프로덕션 신뢰성에 필수적입니다: 초기화 hook(onModuleInit, onApplicationBootstrap)은 의존성이 준비되면 적절한 시점에 설정이 일어나도록 보장하고, shutdown hook(onModuleDestroy, onApplicationShutdown)은 우아한 종료를 가능하게 합니다 — 이는 현대 배포에서 필수적입니다(컨테이너/오케스트레이터가 배포와 스케일링 중 끊임없이 SIGTERM을 보내며, 적절한 정리 없이는 연결이 누출되고 활성 요청이 버려져 무중단 배포가 깨집니다).
onModuleInit에서 연결하고 onModuleDestroy에서 연결 해제하는 표준 패턴(예: Prisma/데이터베이스 service)은 일상 NestJS 지식이며, enableShutdownHooks()를 호출해야 한다는 미묘한 요구사항(또는 shutdown hook이 조용히 절대 발동되지 않음)을 아는 것은 실무적이고 놓치기 쉬운 세부 사항입니다.
Lifecycle hook을 숙달하는 것은 리소스와 배포를 올바르게 처리하는 견고하고 프로덕션 준비가 된 NestJS service를 구축하는 일부입니다.