Lifecycle events
Nest ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ฑ ์์๋ Nest๊ฐ ๊ด๋ฆฌํ๋ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋๋ค. Nest๋ ์ฃผ์ ์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ์ ๋ํ ๊ฐ์์ฑ๊ณผ, ํด๋น ์์ ์ ๋ชจ๋, ํ๋ก๋ฐ์ด๋ ๋๋ ์ปจํธ๋กค๋ฌ์์ ๋ฑ๋ก๋ ์ฝ๋๋ฅผ ์คํํ ์ ์๋ ์๋ช ์ฃผ๊ธฐ ํํฌ (lifecycle hook)๋ฅผ ์ ๊ณตํฉ๋๋ค.
์๋ช ์ฃผ๊ธฐ ์์
๋ค์ ๋ค์ด์ด๊ทธ๋จ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ถํธ์คํธ๋ฉ๋ ์์ ๋ถํฐ Node ํ๋ก์ธ์ค๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ์ฃผ์ ์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ ์์๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ ์ฒด ์๋ช ์ฃผ๊ธฐ๋ ๋ค์๊ณผ ๊ฐ์ด ์ธ ๋จ๊ณ๋ก ๋๋ ์ ์์ต๋๋ค: ์ด๊ธฐํ (initializing), ์คํ (running), ์ข ๋ฃ (terminating). ์ด ์๋ช ์ฃผ๊ธฐ๋ฅผ ํ์ฉํ๋ฉด ๋ชจ๋๊ณผ ์๋น์ค์ ์ ์ ํ ์ด๊ธฐํ, ํ์ฑ ์ฐ๊ฒฐ ๊ด๋ฆฌ, ์ข ๋ฃ ์ ํธ ์์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์์ ์ธ ์ข ๋ฃ๋ฅผ ๊ณํํ ์ ์์ต๋๋ค.
์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ
์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ถํธ์คํธ๋ฉ ๋ฐ ์ข ๋ฃ ๊ณผ์ ์์ ๋ฐ์ํฉ๋๋ค. Nest๋ ๊ฐ ์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ ์์ ์ ๋ํด ๋ชจ๋, ํ๋ก๋ฐ์ด๋, ์ปจํธ๋กค๋ฌ์ ๋ฑ๋ก๋ ์๋ช ์ฃผ๊ธฐ ํํฌ ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค (๋จ, ์ข ๋ฃ ํํฌ๋ ์๋ ์ค๋ช ์ฒ๋ผ ๋จผ์ ํ์ฑํํด์ผ ํฉ๋๋ค). ์์ ๋ค์ด์ด๊ทธ๋จ์์ ๋ณด๋ฏ, Nest๋ ์ฐ๊ฒฐ์ ์์ ํ๊ธฐ ์์ํ๊ฑฐ๋ ์ค๋จํ๊ธฐ ์ํด ๋ด๋ถ ๋ฉ์๋๋ ํธ์ถํฉ๋๋ค.
๋ค์ ํ์์ onModuleInit๊ณผ onApplicationBootstrap์ app.init() ๋๋ app.listen()์ ๋ช ์์ ์ผ๋ก ํธ์ถํ์ ๋๋ง ํธ๋ฆฌ๊ฑฐ ๋ฉ๋๋ค.
๋ํ onModuleDestroy, beforeApplicationShutdown, onApplicationShutdown์ app.close()๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ๊ฑฐ๋, ํ๋ก์ธ์ค๊ฐ SIGTERM๊ณผ ๊ฐ์ ์์คํ ์ข ๋ฃ ์ ํธ๋ฅผ ์์ ํ์ ๋, ๊ทธ๋ฆฌ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ๋ถํธ์คํธ๋ฉ ์ enableShutdownHooks๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ํธ์ถํ ๊ฒฝ์ฐ์๋ง ํธ๋ฆฌ๊ฑฐ ๋ฉ๋๋ค (์์ธํ ๋ด์ฉ์ ์๋ "Application shutdown" ํญ๋ชฉ ์ฐธ์กฐ).
์๋ช ์ฃผ๊ธฐ ํํฌ ๋ฉ์๋ | ํํฌ ๋ฉ์๋ ํธ์ถ์ ํธ๋ฆฌ๊ฑฐํ๋ ์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ |
onModuleInit() | ํด๋น ๋ชจ๋์ ์์กด์ฑ์ด ๋ชจ๋ ํด๊ฒฐ๋ ํ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค. |
onApplicationBootstrap() | ๋ชจ๋ ๋ชจ๋์ด ์ด๊ธฐํ๋ ํ, ์ฐ๊ฒฐ ์์ ์ ์์ํ๊ธฐ ์ ์ ํธ์ถ๋ฉ๋๋ค. |
onModuleDestroy() | ์ข ๋ฃ ์ ํธ (SIGTERM ๋ฑ)๋ฅผ ์์ ํ ํ ํธ์ถ๋ฉ๋๋ค. |
beforeApplicationShutdown() | ๋ชจ๋ onModuleDestroy() ํธ๋ค๋ฌ๊ฐ ์๋ฃ๋ ํ ํธ์ถ๋๋ฉฐ (Promise๊ฐ resolve ๋๋ reject๋ ์ํ), ์ด ๋จ๊ณ๊ฐ ๋๋๋ฉด ๊ธฐ์กด ์ฐ๊ฒฐ์ด ๋ชจ๋ ๋ซํ๋๋ค (app.close() ํธ์ถ๋จ). |
onApplicationShutdown() | ์ฐ๊ฒฐ์ด ๋ชจ๋ ๋ซํ ํ (app.close()๊ฐ resolve๋ ํ) ํธ์ถ๋ฉ๋๋ค. |
* ์ ์ด๋ฒคํธ๋ค์ ๊ฒฝ์ฐ, app.close()๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ์ง ์๋๋ค๋ฉด, SIGTERM ๊ฐ์ ์์คํ ์ข ๋ฃ ์ ํธ์ ๋ฐ์ํ๊ฒ ํ๋ ค๋ฉด ๋ณ๋๋ก ํ์ฑํํด์ผ ํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ ์๋ "Application shutdown" ์น์ ์ ์ฐธ๊ณ ํ์ธ์.
์ฃผ์
์์ ๋์ด๋ ์๋ช ์ฃผ๊ธฐ ํํฌ๋ค์ request-scoped ํด๋์ค์๋ ํธ์ถ๋์ง ์์ต๋๋ค. request scope ํด๋์ค๋ ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ์ ์ฐ๊ฒฐ๋์ด ์์ง ์์ผ๋ฉฐ, ์๋ช ์ด ์์ธก ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ค์ ๊ฐ ์์ฒญ๋ง๋ค ๋ณ๋๋ก ์์ฑ๋๋ฉฐ, ์๋ต์ด ์๋ฃ๋๋ฉด ์๋์ผ๋ก garbage-collected ๋ฉ๋๋ค.
ํํธ
onModuleInit()๊ณผ onApplicationBootstrap()์ ์คํ ์์๋ ๋ชจ๋์ import ์์์ ์ง์ ์ ์ผ๋ก ์์กดํ๋ฉฐ, ์ด์ ํํฌ๊ฐ ์๋ฃ๋ ๋๊น์ง ๋๊ธฐํฉ๋๋ค.
์ฌ์ฉ
๊ฐ ์๋ช ์ฃผ๊ธฐ ํํฌ๋ ์ธํฐํ์ด์ค๋ก ํํ๋ฉ๋๋ค. ์ด ์ธํฐํ์ด์ค๋ค์ TypeScript ์ปดํ์ผ ํ์๋ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ธฐ์ ์ ์ผ๋ก๋ ์ ํ ์ฌํญ์ด์ง๋ง, ๊ฐํ ํ์ ์ง์๊ณผ ์๋ํฐ ๋๊ตฌ์ ๋์์ ๋ฐ๊ธฐ ์ํด์๋ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ ๊ด๋ก์ ๋๋ค. ์๋ช ์ฃผ๊ธฐ ํํฌ๋ฅผ ๋ฑ๋กํ๋ ค๋ฉด, ํด๋น ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ฉด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํน์ ํด๋์ค (์: ์ปจํธ๋กค๋ฌ, ํ๋ก๋ฐ์ด๋, ๋ชจ๋)์์ ๋ชจ๋ ์ด๊ธฐํ ์ ํธ์ถ๋ ๋ฉ์๋๋ฅผ ๋ฑ๋กํ๋ ค๋ฉด, 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์์ dyno ์ข ๋ฃ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฉ๋๋ก ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
์ข ๋ฃ ํํฌ ๋ฆฌ์ค๋๋ ์์คํ ์์์ ์๋นํ๋ฏ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ต๋๋ค. ์ข ๋ฃ ํํฌ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, enableShutdownHooks()๋ฅผ ํธ์ถํ์ฌ ๋ฆฌ์ค๋๋ฅผ ํ์ฑํํด์ผ ํฉ๋๋ค.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// ์ข
๋ฃ ํํฌ ๋ฆฌ์ค๋ ํ์ฑํ
app.enableShutdownHooks();
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
์ฃผ์
ํ๋ซํผ์ ๋ณธ์ง์ ์ธ ์ ํ์ผ๋ก ์ธํด, NestJS๋ Windows์์ ์ ํ๋ฆฌ์ผ์ด์ ์ข ๋ฃ ํํฌ์ ๋ํด ์ ํ์ ์ธ ์ง์๋ง ์ ๊ณตํฉ๋๋ค. SIGINT, SIGBREAK, ๊ทธ๋ฆฌ๊ณ ์ด๋ ์ ๋๋ SIGHUP์ด ์๋ํ ์ ์์ต๋๋ค - ์์ธํ ๋ด์ฉ์ ์ฐธ๊ณ ํ์ธ์, ํ์ง๋ง SIGTERM์ Windows์์ ์ ๋ ์๋ํ์ง ์์ต๋๋ค. ์ด๋ ์์ ๊ด๋ฆฌ์์์ ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ๋ ๊ฒ์ด ๋ฌด์กฐ๊ฑด์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ฆ, "์ ํ๋ฆฌ์ผ์ด์ ์ด ์ด๋ฅผ ๊ฐ์งํ๊ฑฐ๋ ๋ฐฉ์งํ ๋ฐฉ๋ฒ์ด ์๋ค"๋ ๋ป์ ๋๋ค. Windows์์ SIGINT, SIGBREAK ๋ฑ์ด ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง์ ๋ํด์๋ libuv ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์. ๋ํ, Node.js์ Process Signal Events ๋ฌธ์๋ ์ฐธ๊ณ ํ ์ ์์ต๋๋ค.
์ ๋ณด
enableShutdownHooks๋ ๋ฆฌ์ค๋๋ฅผ ์์ํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํฉ๋๋ค. ํ๋์ Node ํ๋ก์ธ์ค์์ ์ฌ๋ฌ Nest ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ์คํํ๋ ๊ฒฝ์ฐ (์: Jest๋ก ๋ณ๋ ฌ ํ ์คํธ ์คํ ์), Node๊ฐ ๋ฆฌ์ค๋ ์๊ฐ ๊ณผ๋ํ๋ค๊ณ ๊ฒฝ๊ณ ํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ด์ ๋ก enableShutdownHooks๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ง ์์ต๋๋ค. ๋จ์ผ Node ํ๋ก์ธ์ค์์ ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ์คํํ ๋ ์ด ์กฐ๊ฑด์ ๋ฐ๋์ ์ธ์งํ์ธ์.
์ ํ๋ฆฌ์ผ์ด์ ์ด ์ข ๋ฃ ์ ํธ๋ฅผ ์์ ํ๋ฉด, ๋ฑ๋ก๋ onModuleDestroy(), beforeApplicationShutdown(), onApplicationShutdown() ๋ฉ์๋๋ฅผ ํด๋น ์์๋๋ก ํธ์ถํ๋ฉฐ, ์ด๋ ํด๋น ์ ํธ๋ฅผ ์ฒซ ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํฉ๋๋ค. ๋ฑ๋ก๋ ํจ์๊ฐ ๋น๋๊ธฐ ํธ์ถ์ await ํ๋ ๊ฒฝ์ฐ (Promise๋ฅผ ๋ฐํํ ๊ฒฝ์ฐ), Nest๋ ํด๋น Promise๊ฐ resolve ๋๊ฑฐ๋ reject ๋ ๋๊น์ง ๋ค์ ๋จ๊ณ๋ก ์งํํ์ง ์์ต๋๋ค.
@Injectable()
class UsersService implements OnApplicationShutdown {
onApplicationShutdown(signal: string) {
console.log(signal); // ์: "SIGINT"
}
}
์ ๋ณด
app.close()๋ฅผ ํธ์ถํด๋ Node ํ๋ก์ธ์ค๋ ์ข ๋ฃ๋์ง ์์ผ๋ฉฐ, ๋จ์ง onModuleDestroy()์ onApplicationShutdown() ํํฌ๋ง ํธ๋ฆฌ๊ฑฐ ๋ฉ๋๋ค. ๋ฐ๋ผ์, ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ ์ค์ธ interval, ์ ๊ธฐ ์คํ ์์ ๋ฑ์ด ์๋ค๋ฉด ํ๋ก์ธ์ค๋ ์๋์ผ๋ก ์ข ๋ฃ๋์ง ์์ต๋๋ค.
Discovery service
@nestjs/core ํจํค์ง์์ ์ ๊ณตํ๋ DiscoveryService๋ NestJS ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ ํ๋ก๋ฐ์ด๋, ์ปจํธ๋กค๋ฌ ๋ฐ ๊ธฐํ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋์ ์ผ๋ก ํ์ํ๊ณ ๊ฐ์ ธ์ฌ ์ ์๊ฒ ํด ์ฃผ๋ ๊ฐ๋ ฅํ ์ ํธ๋ฆฌํฐ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ํนํ ํ๋ฌ๊ทธ์ธ, ๋ฐ์ฝ๋ ์ดํฐ ๋๋ ๋ฐํ์ ๋ฆฌํ๋ ์ ์ ์์กดํ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ๊ตฌ์ถํ ๋ ์ ์ฉํฉ๋๋ค. DiscoveryService๋ฅผ ํ์ฉํ๋ฉด ๋ ์ ์ฐํ๊ณ ๋ชจ๋ํ ๋ ์ํคํ ์ฒ๋ฅผ ์ค๊ณํ ์ ์์ผ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋ํ ๋ฐ ๋์ ๋์์ ๊ตฌํํ ์ ์์ต๋๋ค.
์์ํ๊ธฐ
DiscoveryService๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์, ์ด๋ฅผ ์ฌ์ฉํ ๋ชจ๋์ DiscoveryModule์ Import ํด์ผ ํฉ๋๋ค. ์ด ๊ณผ์ ์ ํตํด DiscoveryService๊ฐ ์์กด์ฑ ์ฃผ์ ๋์์ผ๋ก ๋ฑ๋ก๋ฉ๋๋ค. ๋ค์์ NestJS ๋ชจ๋์์ ์ด๋ฅผ ์ค์ ํ๋ ์์์ ๋๋ค:
import { Module } from '@nestjs/common';
import { DiscoveryModule } from '@nestjs/core';
import { ExampleService } from './example.service';
@Module({
imports: [DiscoveryModule],
providers: [ExampleService],
})
export class ExampleModule {}
๋ชจ๋ ์ค์ ์ด ์๋ฃ๋๋ฉด, DiscoveryService๋ ๋์ ํ์์ด ํ์ํ ์ด๋ค ํ๋ก๋ฐ์ด๋๋ ์๋น์ค์๋ ์ฃผ์ ํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@Injectable()
export class ExampleService {
constructor(private readonly discoveryService: DiscoveryService) {}
}
ํ๋ก๋ฐ์ด๋ ๋ฐ ์ปจํธ๋กค๋ฌ ํ์ํ๊ธฐ
DiscoveryService์ ํต์ฌ ๊ธฐ๋ฅ ์ค ํ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฑ๋ก๋ ๋ชจ๋ ํ๋ก๋ฐ์ด๋๋ฅผ ์กฐํํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ํ๋ก๋ฐ์ด๋๋ฅผ ๋์ ์ผ๋ก ์ฒ๋ฆฌํ ๋ ์ ์ฉํฉ๋๋ค. ๋ค์ ์ฝ๋๋ ๋ชจ๋ ํ๋ก๋ฐ์ด๋์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
const providers = this.discoveryService.getProviders();
console.log(providers);
๊ฐ ํ๋ก๋ฐ์ด๋ ๊ฐ์ฒด์๋ ์ธ์คํด์ค, ํ ํฐ, ๋ฉํ๋ฐ์ดํฐ ๋ฑ์ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฑ๋ก๋ ๋ชจ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์กฐํํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ต๋๋ค:
const controllers = this.discoveryService.getControllers();
console.log(controllers);
์ด ๊ธฐ๋ฅ์ ์ปจํธ๋กค๋ฌ๋ฅผ ๋์ ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ ์ํฉ, ์๋ฅผ ๋ค์ด ๋ถ์ ์ถ์ (analytics tracking)์ด๋ ์๋ ๋ฑ๋ก ๋ฉ์ปค๋์ฆ๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ํนํ ์ ์ฉํฉ๋๋ค.
๋ฉํ๋ฐ์ดํฐ ์ถ์ถํ๊ธฐ
ํ๋ก๋ฐ์ด๋ ๋ฐ ์ปจํธ๋กค๋ฌ๋ฅผ ํ์ํ๋ ๊ฒ์ ๋์ด, DiscoveryService๋ ์ด๋ฌํ ๊ตฌ์ฑ ์์์ ๋ถ์ฐฉ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋ฐํ์์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ปค์คํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ ๋ ํนํ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํน์ ๋ฉํ๋ฐ์ดํฐ๋ก ํ๋ก๋ฐ์ด๋๋ฅผ ํ๊ทธ ํ๋ ์ปค์คํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด ๋ด ์๋ค:
import { DiscoveryService } from '@nestjs/core';
export const FeatureFlag = DiscoveryService.createDecorator();
์ด ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์๋น์ค์ ์ ์ฉํ๋ฉด, ํด๋น ์๋น์ค์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ผ๋ฉฐ, ์ด ๋ฉํ๋ฐ์ดํฐ๋ ๋์ค์ ์กฐํํ ์ ์์ต๋๋ค.
import { Injectable } from '@nestjs/common';
import { FeatureFlag } from './custom-metadata.decorator';
@Injectable()
@FeatureFlag('experimental')
export class CustomService {}
์ด์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ฉํ๋ฐ์ดํฐ๊ฐ ํ๋ก๋ฐ์ด๋์ ๋ถ์ฐฉ๋๋ฉด, DiscoveryService๋ฅผ ์ฌ์ฉํด ํด๋น ๋ฉํ๋ฐ์ดํฐ ๊ฐ์ ๋ฐ๋ผ ํ๋ก๋ฐ์ด๋๋ฅผ ์ฝ๊ฒ ํํฐ๋งํ ์ ์์ต๋๋ค. ๋ค์ ์ฝ๋๋ ํน์ ๋ฉํ๋ฐ์ดํฐ ๊ฐ์ผ๋ก ํ๊ทธ ๋ ํ๋ก๋ฐ์ด๋๋ฅผ ์กฐํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค:
const providers = this.discoveryService.getProviders();
const [provider] = providers.filter(
(item) =>
this.discoveryService.getMetadataByDecorator(FeatureFlag, item) ===
'experimental',
);
console.log(
'Providers with the "experimental" feature flag metadata:',
provider,
);
๊ฒฐ๋ก
DiscoveryService๋ NestJS ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐํ์ ๋ฆฌํ๋ ์ ์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๋ค์ฌ๋ค๋ฅํ๊ณ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. ํ๋ก๋ฐ์ด๋, ์ปจํธ๋กค๋ฌ, ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋์ ์ผ๋ก ํ์ํ ์ ์๋๋ก ํจ์ผ๋ก์จ, ํ์ฅ ๊ฐ๋ฅํ ํ๋ ์์ํฌ, ํ๋ฌ๊ทธ์ธ, ์๋ํ ๊ธฐ๋ฐ ๊ธฐ๋ฅ์ ๊ตฌ์ถํ๋ ๋ฐ ํต์ฌ์ ์ธ ์ญํ ์ ํฉ๋๋ค. ํ๋ก๋ฐ์ด๋๋ฅผ ์ค์บ ๋ฐ ์ฒ๋ฆฌํ๊ฑฐ๋, ๊ณ ๊ธ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๊ฑฐ๋, ๋ชจ๋ํ ๋๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ํคํ ์ฒ๋ฅผ ๋ง๋ค๊ณ ์ ํ ๋, DiscoveryService๋ ์ด๋ฌํ ๋ชฉํ๋ฅผ ๋ฌ์ฑํ๊ธฐ ์ํ ํจ์จ์ ์ด๊ณ ๊ตฌ์กฐํ๋ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
Reference
'๐ ๊ณต์ ๋ฌธ์ ๋ฒ์ญ > Nest.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Nest.js] Fundamentals | Platform agnosticism, Testing (3) | 2025.07.29 |
---|---|
[Nest.js] Fundamentals | Lazy-loading modules, Execution context (3) | 2025.07.29 |
[Nest.js] Fundamentals - Circular dependency, Module reference (0) | 2025.07.19 |
[Nest.js] Fundamentals - Dynamic modules, Injection scopes (0) | 2025.07.16 |
[Nest.js] Fundamentals - Custom providers, Asynchronous providers (0) | 2025.07.15 |