Node.js 모범 사례 - 에러 처리 방법(3)

전도해·2022년 10월 17일

Node.js Best Practices

목록 보기
4/4
post-thumbnail

APM 제품을 사용하여 에러와 다운타임을 확인하라

애플리케이션 오류는 느린 코드 경로, API 다운타임, 계산 리소스 부족 등의 형태로 발생할 수 있습니다.
APM 제품을 사용한다면, 아래와 같은 문제들을 사전에 감지할 수 있습니다.

1) HTTP API가 오류를 반환할 때 경고
2) API 응답 시간이 일부 임계값 아래로 떨어질 때 감지
3) 'Code Smell' 감지
4) 서버 리소스 모니터링 기능
5) IT 메트릭이 포함된 운영 인텔리전스 대시보드 등

APM 제품은 3가지 주요 부문으로 구성됩니다.

1) 웹 사이트 또는 API 모니터링 – HTTP 요청을 통해 가동 시간과 성능을 지속적으로 모니터링하는 외부 서비스입니다.
예) Pingdom, Uptime Robot, New Relic

2) 코드 계측 – 느린 코드 감지, 예외 통계, 성능 모니터링 등과 같은 기능을 사용하기 위해 애플리케이션 내에 에이전트를 내장해야 하는 제품군입니다.
예) New Relic, App Dynamics

3) 운영 인텔리전스 대시보드 – 이 제품군은 애플리케이션 성능을 쉽게 파악하는 데 도움이 되는 메트릭 및 선별된 콘텐츠로 운영 팀을 촉진하는 데 중점을 두고 있습니다. 여기에는 일반적으로 여러 정보 소스(애플리케이션 로그, DB 로그, 서버 로그 등)를 집계하고 사전 대시보드 디자인 작업이 포함됩니다.
예) Datadog , Splunk , Zabbix




처리되지 않은 promise 거부(unhandled promise rejection)를 잡아라

보통 대부분의 최신 Node.js/Express 애플리케이션 코드는
.then 메소드, 콜백함수 또는 catch 블록(try, catch) 같은 비동기 처리방식으로 실행됩니다

놀랍게도 개발자가 .catch 절을 추가하는 것을 기억하지 않는 한 이러한 위치에서 발생한 오류는 uncaughtException 이벤트 처리기에 의해 처리되지 않고 사라집니다.

최신 버전의 Node에는 unhandled rejection가 표시될 때 경고 메시지가 추가되었으나, 이는 상황이 잘못됨을 알아차리는 데 도움이 되는 정도이고 분명히 적절한 오류 처리 방법은 아닙니다.

간단한 솔루션은 각 약속 체인 호출 내에 .catch 절을 추가하는 것을 잊지 않고 중앙 집중식 오류 처리기로 리디렉션하는 것입니다.
그러나 개발자의 원칙에 따라 오류 처리 전략을 구축하는 것은 다소 취약합니다.

따라서 적절한 대체를 사용하고 아래와 같은 방법을 이용하는 것이 좋습니다.
process.on(‘unhandledRejection’, callback) – 이는 로컬에서 처리되지 않는 경우 모든 비동기 오류가 처리되도록 합니다.


아래와 같은 오류는 오류 처리기에 의해 포착되지 않습니다.

DAL.getUserById(1).then((johnSnow) => {
  // this error will just vanish
  if(johnSnow.isAlive == false)
      throw new Error('ahhhh');
});

unresolved, rejected 에러 잡기

process.on('unhandledRejection', (reason, p) => {
  throw reason;
});
process.on('uncaughtException', (error) => {
  errorManagement.handler.handleError(error);
  if (!errorManagement.handler.isTrustedError(error))
    process.exit(1);
});

다음 중 콘솔에 오류를 출력할 것으로 예측되는 건 몇 번일까요?

// 1
Promise.resolve(‘promised value’).then(() => {
  throw new Error(‘error’);
});

// 2
Promise.reject(‘error value’).catch(() => {
  throw new Error(‘error’);
});

// 3
new Promise((resolve, reject) => {
  throw new Error(‘error’);
});

James Nelson의 블로그에 따르면 많은 최신 자바스크립트 환경에서 위 코드는 오류를 출력하지 않을 것이라고 합니다.

따라서 묻히는(버려지는) 오류 없이 위와 같은 방법으로 처리해야 합니다.




전용 라이브러리를 이용해 인자값이 유효한지 검사하여 빠르게 실패하라(Fail Fast)

우리 모두는 숨겨진 버그를 피하기 위해 인수를 확인하고 빠르게 실패하는 것이 얼마나 중요한지 알고 있습니다. JoiValidator와 같은 라이브러리는 이 작업을 효율적으로 도와줍니다.


유효성 검사가 없을 때의 안티 패턴

// if the discount is positive let's then redirect the user to print his discount coupons
function redirectToPrintDiscount(httpResponse, member, discount) {
    if (discount != 0) {
        httpResponse.redirect(`/discountPrintView/${member.id}`);
    }
}

redirectToPrintDiscount(httpResponse, someMember);
// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?

'Joi'를 사용한 복잡한 JSON 입력 유효성 검사

var memberSchema = Joi.object().keys({
 password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
 birthyear: Joi.number().integer().min(1900).max(2013),
 email: Joi.string().email()
});

function addNewMember(newMember) {
 // assertions come first
 Joi.assert(newMember, memberSchema); //throws if validation fails
 // other logic here
}
profile
우리는 사실 노력하지 않는 천재일지도..? 🤔

0개의 댓글