개발

[NestJS] 병목현상으로 서버지연 타임아웃 처리로 해결

프로앤트 2025. 7. 29. 09:54

저흰 내부적으로 백엔드는 Nestjs서비스를 사용하고 있습니다.

태생이 php 태생이였던 저에게 TypeScript 언어는 조금 생소하긴했지만 이렇게 사용한지 언 3년 가까이 되어가네요.

 

짧다면 짧고 길다면 긴 시간, 작동 방식부터 전반적인 시스템이 다르다보니 오류 검증 및 서버 운영에 여러 어려움이 있었는데요.

 

저희는 내부적으로는 카카오워크를 사용하고 있기에, 다양한 오류는 카카오워크로 전달 받도록 해놓았는데요.

 

 

 

최근 사용자가 늘기도 했고, 원래 사용자가 적지 않았던 서비스였던 터라 신규 앱을 출시 하고 나서 한동안 잠잠하던 병목현상을 마주하게 되었습니다.

 

 

이게 서버자체는 죽지 않고, 메모리도 어느정도 여유가 있는 상태인데다, 호출자체가 안되는것 같진 않더라구요. 드문드문 호출 및 처리가 진행되는거보니 서버 문제가 아닌것 같은데 왜그러지? 라는 생각을 하고 있던 상황에서 발견했던 트랜젝션 문제와 DB쿼리 문제.

 

(개인적으로 트랜젝션은 정말 필요한곳 아니면 잘 안쓰게 됩니다. )

 

 

일단 회원쪽 테이블이 잠김과 동시에 트렌젝션도 걸리니 DB는 이중고였던 상황이였네요.

 

거기다가 트랜젝션이 한두개 걸린다고 DB에 병목증상이 나오는게 아니니 발생시기도 랜덤.

 

결국 인터셉터를 통해 발생시 20초를 초과하는 오류는 중지하는걸 만들었고, 중지시 오류메시지가 발생하기때문에 카카오 워크로 전달 받는 로직으로 구성했다.

 

 

이후 지연이 생기는 서비스 항목은 따로 개선을 진행하게 되었는데

 

별거 없지만, 별것 이였던 서비스에 대해 정리해보려고 한다.

 

아래는 인터셉터 입니다. 서비스 전반적으로 작동하게되며 20초가 지나는 경우, 타임아웃을 걸어버리는 아주 좋은 친구죠

적당한곳에 파일을 만들면 되겠습니다.

 

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
  RequestTimeoutException,
} from "@nestjs/common"
import { catchError, Observable, throwError, timeout } from "rxjs"

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      timeout(20000), // 20초
      catchError((err) => {
        if (err.name === "TimeoutError") {
          return throwError(
            () => new RequestTimeoutException("요청이 20초를 초과했습니다.")
          )
        }
        return throwError(() => err)
      })
    )
  }
}

 

 

그리고 나서 Nestjs서비스의 시작점인 main.ts에 해당 인터셉터를 연결해줍니다.

  const app = await NestFactory.create(AppModule)
  app.useGlobalInterceptors(new TimeoutInterceptor())
  await app.listen(port, "0.0.0.0")

 

이렇게 해주시면 타임아웃이 걸리면 차단되기때문에 적어도 병목현상은 겪지 않으실것 같습니다.