NestJS 애플리케이션 내 Health Check 추가

이번 글에서는 NextJS 애플리케이션 개발 시 Health Check 모듈을 추가하는 방법에 대해 살펴보도록 하겠습니다. 일반적인 NodeJS 개발 시 Health Check 방법에 대해서는 아래 글을 참고하시길 바랍니다.

Node.js 내 Health Check 설정 방법

NestJS 애플리케이션에서 상태 확인 추가

상태 확인 엔드포인트는 애플리케이션이 수행되는 방식에 대한 세부 정보를 제공합니다. 상태 확인 기능을 추가하는 이유는 뭘까요? 


애플리케이션을 빌드하고 배포한 후에는 일부 애플리케이션 비즈니스 로직을 호출하지 않고도 보다 쉬운 방식으로 애플리케이션이 원활하게 실행되고 있는지 알아야 합니다. 상태 확인은 데이터베이스가 원활하게 실행되고 있는지, 스토리지 디스크가 정상인지, 애플리케이션 서비스가 의도한 대로 실행되고 있는지 확인할 수 있는 방법을 제공합니다.

상태 확인이 필요한 가장 중요한 이유는 애플리케이션을 계속 모니터링할 수 있기 때문입니다. 메트릭 수집 서비스(예: Micrometer)는 애플리케이션을 계속 검증할 수 있고, 소프트웨어 또는 하드웨어 오류가 없는지 확인할 수 있습니다.

소프트웨어 또는 하드웨어 오류가 발생하면 언제든지 수동 또는 자동 개입에 대한 알림을 트리거하여 응용 프로그램을 정상 상태로 되돌릴 수 있습니다. 이는 애플리케이션의 신뢰성을 향상시킵니다.

NestJS 애플리케이션의 상태 확인

NestJS 프레임워크에서 Terminus 라이브러리는 준비/활성 상태 확인을 통합하는 방법을 제공합니다. 인프라의 서비스 또는 구성 요소는 지속적으로 GET 엔드포인트에 도달합니다. 서비스는 응답에 따라 조치를 취하게 됩니다.

먼저 NestJS 애플리케이션에 터미널 라이브러리를 추가합시다.

npm install @nestjs/terminus.


Terminus 통합은 http 애플리케이션에 대한 쿠버네티스 준비성/활성도 검사는 물론 정상적인 종료를 제공합니다. 활성 확인은 컨테이너가 실행 중인지 알려줍니다. 준비 확인은 컨테이너가 들어오는 요청을 수락할 준비가 되었는지 알려줍니다.

또한 이 게시물에서 데이터베이스, 메모리, 디스크 및 redis에 대한 여러 검사를 설정하여 상태 검사가 작동하는 방식을 보여줍니다.

NestJS 내 상태 확인 설정 방법

nestjs/terminus 패키지를 추가하면 상태 확인 엔드포인트를 생성하고 사전 정의된 지표를 포함할 수 있습니다. 이러한 지표에는 HTTP 확인, 데이터베이스 연결 확인, 메모리 및 디스크 확인이 포함됩니다.

사용 중인 ORM에 따라 nestjs는 TypeORM 또는 Sequlize 상태 확인 표시기와 같은 내장 패키지를 제공합니다. 상태 확인은 지표 조합을 제공합니다. 이 표시기 세트는 애플리케이션이 어떻게 작동하는지 나타내는 정보를 제공합니다.

디스크 상태 표시기

서버의 하드 디스크가 어떻게 작동하는지부터 시작하겠습니다. DiskHealthIndicator에는 현재 시스템의 디스크 저장소에 대한 검사가 포함되어 있습니다. 상태 컨트롤러에 DiskHealthIndicator를 추가하면 다음과 같이 스토리지를 확인합니다.

this.disk.checkStorage('diskStorage', { thresholdPercent: 0.5, path: 'C:\\'});

HttpHealthIndicator


HttpHealthIndicator는 HTTP 애플리케이션의 세부 정보와 실행 여부를 제공합니다. 명시적으로 @nestjs/axios 패키지를 프로젝트에 추가합니다.

npm install @nestjs/axios.

추가로. pingCheck 메서드를 사용하여 애플리케이션에 연결할 수 있는지 확인합니다.

this.http.pingCheck('Basic check', 'http://localhost:3000');

MemoryHealthIndicator

전반적으로 MemoryHealthIndicator는 애플리케이션이 실행 중인 시스템의 메모리 세부 정보를 제공합니다.

this.memory.checkHeap('memory_heap', 300*1024*1024);

this.memory.checkRSS('memory_rss',300*1024*1024);

데이터베이스 상태 확인

애플리케이션이 데이터베이스를 사용한다고 가정하면 데이터베이스 상태 확인이 필요합니다. 결과적으로 nestjs/terminus는 TypeORM, Sequelize 또는 Mongoose와 같은 ORM 패키지를 통해 데이터베이스 상태 검사를 제공합니다. 이 데모의 일부로 Prisma ORM을 사용하므로 사용자 지정 데이터베이스 상태 확인을 생성합니다.

NestJS 애플리케이션

이제 nestjs/cli로 nestjs 애플리케이션을 만들어 봅시다.

nest new healthcheckdemo.

앞에서 언급했듯이 Prisma ORM을 사용합니다.

npm install prisma --save-dev.

그러면 Prisma cli가 설치됩니다. 이제 npx prisma init 를 실행하면 데이터베이스 모델 스키마를 생성할 schema.prisma 파일의 베어본이 생성됩니다.

이 애플리케이션에서는 사용자가 가입하여 게시물을 작성할 수 있는 간단한 스키마를 사용하고 있습니다. 저도 MySQL 데이터베이스를 사용하고 있습니다. 이 스키마는 아래와 같습니다.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
  engineType = "binary"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id    Int     @default(autoincrement()) @id
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @default(autoincrement()) @id
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

기본적으로 Prisma는 이전에 없었던 .env 파일을 생성합니다. 또한 DATABASE_URL에 대한 기본 변수를 추가합니다. npm run prisma migrate dev를 실행하면 DB에 해당 데이터베이스 테이블이 생성됩니다. 또한 healthcheckdemo용 샘플 애플리케이션에서 앱 모듈을 생성해 보겠습니다.

import { Module } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserService } from './user.service';
import { HealthModule } from './health/health.module';
import { HttpModule } from '@nestjs/axios';
import { PrismaService } from './prisma.service';

@Module({
  imports: [HealthModule, HttpModule],
  controllers: [AppController],
  providers: [AppService, UserService, PrismaClient, PrismaService,],
})
export class AppModule {}

또한 HealthController의 용도에 맞는 HealthModule을 만들 것입니다.

import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { PrismaService } from 'src/prisma.service';

import { HealthController } from './health.controller';
import { PrismaOrmHealthIndicator } from './prismaorm.health';

@Module({
  imports: [
    TerminusModule,   
  ],
  controllers: [HealthController],
  providers: [ PrismaOrmHealthIndicator, PrismaService]
})
export class HealthModule {}

이 HealthModule에는 PrismaOrmHealthIndicator가 있음을 알 수 있습니다. PrismaOrmHealthIndicator에 들어가기 전에 Prisma 클라이언트를 생성해야 합니다.

npm install @prisma/client는 데이터베이스 모델에 대한 Prisma 클라이언트를 생성합니다. 이렇게 하면 데이터베이스 모델에 대한 CRUD 작업이 노출되어 개발자가 데이터베이스에서 데이터에 액세스하는 방법보다 비즈니스 논리에 더 쉽게 집중할 수 있습니다.

Prisma 클라이언트 API를 추상화하여 별도의 서비스 PrismaService에서 데이터베이스 쿼리를 생성합니다. 이 서비스는 또한 Prisma 클라이언트를 인스턴스화합니다.

import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}
error: Content is protected !!