노드에서 예외 처리는 정말 중요하다. 예외란 보통 처리하지 못한 에러를 가리킨다. 이러한 예외들은 실행 중인 노드 프로세스를 멈추가 만든다.

멀티 스레드 프로그램에서는 스레드 하나가 멈추면 그 일을 다른 스레드가 대신한다. 하지만 노드는 메인 스레드가 하나뿐이라 조심해야한다. 메인 스레드가 에러로 인해 멈춘다는 것은 스레드를 갖고 있는 프로세스가 멈춘다는 뜻이고, 전체 서버도 멈춘다는 뜻과 같다.

따라서 에러 로그가 기록되더라도 작업은 계속 진행될 수 있도록. 에러를 처리하는 방법을 익혀두어야 한다.

보통은 에러가 발생할 것 같은 부분을 try/catch 문으로 감싸면 된다.

setInterval(() => {
  console.log('start!!');
  try {
    throw new Error('Error!!!!!!!');
  } catch (err) {
    console.error(err);
  }
}, 1000);

위 소스를 실행시켜보면 에러를 강제로 발생시켜서 1초마다 에러를 출력하며 인터벌이 작동한다. 프로세스가 중단되지 않는다. try/catch문을 제거하면 에러가 찍힘과 동시에 프로세스가 중단된다. throw 로 에러를 발생시키면 에러 로그을 출력하면서 프로세스가 중단된다. 중단시키지 않으려면 try/catch문으로 감싸야한다.

예측 불가능한 에러 처리 방법

process.on('uncaughtException', (err) => {
  console.error('예기치 못한 에러', err)
})

setInterval(() => {
  throw new Error('서버 멈춰!!');
}, 1000);

setInterval(() => {
  console.log('시작!!!');
}, 2000);

process 객체에 uncaughtException 이벤트 리스너를 달면 처리하지 못한 에러가 발생했을 때 이벤트 리스너가 실행되고 프로세스가 유지된다. 위 소스에서 이벤트리스너 부분을 제거하면 첫 인터벌에 try/catch가 없기 때문에 에러가 발생하면서 프로세스가 종료된다.

노드 공식 문서에서는 uncaughtException 이벤트를 최후의 수단으로 사용할 것을 명시하고 있다. 노드는 uncaughtException 이벤트 발생 후 다음 동작이 제대로 동작하는지 보증하지 않는다. 단순히 에러 내용을 기록하는 정도로 사용하고, 에러를 기록한 후 process.exit()으로 프로세스를 종료하는 것이 좋다.

process.on('uncaughtException', (err) => {
  console.error('예기치 못한 에러', err)
  process.exit();
})

setInterval(() => {
  throw new Error('서버 멈춰!!');
}, 1000);

setInterval(() => {
  console.log('시작!!!');
}, 2000);

종료하지 않으면 에러가 발생하는 코드를 수정하기 전까지 프로세스가 실행되는 동안 에러가 계속 발생할 것이다. 물론 상황에 따라 종료를 할지 않할지 정하는게 맞는듯...