Node.js 인터뷰 질문 20

질문: Node.js의 process 객체에 대해 설명하고 주요 사용법을 알려주세요.

답변:

Node.js의 process 객체는 현재 실행 중인 Node.js 프로세스에 대한 정보를 제공하고 제어할 수 있는 전역 객체입니다. 이 객체는 별도로 require할 필요 없이 모든 Node.js 애플리케이션에서 바로 사용할 수 있습니다.

process 객체의 주요 속성

1. 환경 변수 (process.env)

process.env는 운영체제의 환경 변수에 접근할 수 있게 해주는 객체입니다.

// 환경 변수 접근
console.log(process.env.NODE_ENV); // 'development', 'production' 등
console.log(process.env.HOME); // 사용자 홈 디렉토리
console.log(process.env.PATH); // 시스템 경로

// 환경 변수 설정
process.env.MY_VARIABLE = "value";

환경 변수는 애플리케이션 설정, 데이터베이스 연결 정보, API 키 같은 민감한 정보를 코드와 분리하는 데 자주 사용됩니다.

2. 명령줄 인수 (process.argv)

process.argv는 명령줄 인수를 담고 있는 배열입니다.

// 파일: app.js
console.log(process.argv);

// 실행: node app.js arg1 arg2
// 출력:
// [
//   '/usr/local/bin/node',  // Node.js 실행 파일 경로
//   '/path/to/app.js',      // 실행 중인 스크립트 경로
//   'arg1',                 // 첫 번째 명령줄 인수
//   'arg2'                  // 두 번째 명령줄 인수
// ]

명령줄 인수를 쉽게 파싱하기 위해 yargs, commander 같은 패키지를 함께 사용하는 경우가 많습니다.

3. 현재 작업 디렉토리 (process.cwd())

process.cwd()는 현재 Node.js 프로세스가 실행 중인 디렉토리 경로를 반환합니다.

console.log(process.cwd()); // '/path/to/current/directory'

// 작업 디렉토리 변경
process.chdir("/new/directory");
console.log(process.cwd()); // '/new/directory'

4. 프로세스 ID (process.pid)

process.pid는 현재 프로세스의 ID를 제공합니다.

console.log(`이 프로세스의 ID는 ${process.pid}입니다.`);

5. 플랫폼 정보 (process.platform)

process.platform은 프로세스가 실행 중인 운영체제 플랫폼을 식별합니다.

console.log(process.platform);
// 'darwin', 'win32', 'linux' 등

6. Node.js 버전 (process.version)

process.version은 현재 사용 중인 Node.js의 버전을 반환합니다.

console.log(process.version); // 'v16.14.0' 등

7. 메모리 사용량 (process.memoryUsage())

process.memoryUsage()는 현재 프로세스의 메모리 사용량에 대한 정보를 제공합니다.

console.log(process.memoryUsage());
// {
//   rss: 30728192,          // Resident Set Size: 프로세스가 사용 중인 물리적 메모리 양
//   heapTotal: 5922816,     // V8 힙에 할당된 총 메모리
//   heapUsed: 3621248,      // V8 힙에서 실제 사용 중인 메모리
//   external: 877074,       // V8 외부 C++ 객체에 바인딩된 메모리
//   arrayBuffers: 9898      // ArrayBuffer 및 SharedArrayBuffer에 할당된 메모리
// }

process 객체의 주요 메서드

1. 프로세스 종료 (process.exit())

process.exit()는 현재 프로세스를 즉시 종료합니다. 종료 코드를 인수로 전달할 수 있습니다.

// 성공적인 종료
process.exit(0);

// 오류로 인한 종료
process.exit(1);

2. 표준 입출력 스트림

process.stdout, process.stderr, process.stdin은 각각 표준 출력, 표준 오류, 표준 입력 스트림에 대한 접근을 제공합니다.

// 표준 출력에 쓰기
process.stdout.write("Hello, World!\n");

// 표준 오류에 쓰기
process.stderr.write("오류가 발생했습니다!\n");

// 표준 입력에서 읽기
process.stdin.on("data", (data) => {
  console.log(`입력 받음: ${data}`);
});

3. 다음 틱 함수 (process.nextTick())

process.nextTick()은 이벤트 루프의 현재 반복이 완료된 후, I/O 이벤트 콜백보다 먼저 호출될 함수를 예약합니다.

console.log("시작");

process.nextTick(() => {
  console.log("nextTick 콜백");
});

console.log("종료");

// 출력:
// 시작
// 종료
// nextTick 콜백

process.nextTick()setTimeout(fn, 0)보다 더 빠르게 실행되며, 이벤트 루프의 다음 단계로 넘어가기 전에 실행됩니다.

process 이벤트

process 객체는 EventEmitter이므로 다양한 이벤트를 발생시키고 리스닝할 수 있습니다.

1. exit 이벤트

프로세스가 종료될 때 발생합니다.

process.on("exit", (code) => {
  console.log(`종료 코드: ${code}`);
  // 참고: 이 콜백에서는 비동기 작업을 수행할 수 없습니다.
});

2. uncaughtException 이벤트

처리되지 않은 예외가 발생했을 때 트리거됩니다.

process.on("uncaughtException", (err) => {
  console.error("처리되지 않은 예외:", err);
  // 로그 기록이나 정리 작업 수행
  process.exit(1);
});

주의: uncaughtException은 안전망으로만 사용해야 하며, 정상적인 오류 처리 방식으로 사용해서는 안 됩니다. 프로세스 상태가 불안정할 수 있으므로, 로그를 기록하고 프로세스를 재시작하는 것이 좋습니다.

3. SIGINT, SIGTERM 등의 시그널 이벤트

운영체제 시그널이 프로세스로 전송될 때 발생합니다.

// Ctrl+C가 눌렸을 때
process.on("SIGINT", () => {
  console.log("SIGINT 시그널을 받았습니다(Ctrl+C)");
  process.exit(0);
});

// kill 명령으로 SIGTERM이 전송되었을 때
process.on("SIGTERM", () => {
  console.log("SIGTERM 시그널을 받았습니다");
  // 정리 작업 수행
  server.close(() => {
    process.exit(0);
  });
});

4. warning 이벤트

Node.js에서 경고가 발생할 때 트리거됩니다.

process.on("warning", (warning) => {
  console.warn(`경고 이름: ${warning.name}`);
  console.warn(`경고 메시지: ${warning.message}`);
  console.warn(`스택 트레이스: ${warning.stack}`);
});

실제 사용 예시

1. 환경 변수에 기반한 애플리케이션 설정

// config.js
const config = {
  development: {
    port: 3000,
    databaseUrl: "mongodb://localhost:27017/dev_db",
  },
  production: {
    port: process.env.PORT || 8080,
    databaseUrl: process.env.DATABASE_URL,
  },
  test: {
    port: 3001,
    databaseUrl: "mongodb://localhost:27017/test_db",
  },
};

const env = process.env.NODE_ENV || "development";
module.exports = config[env];
// app.js
const config = require("./config");
const express = require("express");
const app = express();

app.listen(config.port, () => {
  console.log(`서버가 ${config.port} 포트에서 실행 중입니다.`);
});

2. 명령줄 인수를 사용한 CLI 도구

// simple-cli.js
const args = process.argv.slice(2);

if (args.length === 0) {
  console.log("사용법: node simple-cli.js [명령] [인수]");
  process.exit(1);
}

const command = args[0];

switch (command) {
  case "greet":
    const name = args[1] || "Guest";
    console.log(`안녕하세요, ${name}님!`);
    break;
  case "time":
    console.log(`현재 시간은 ${new Date().toLocaleTimeString()}입니다.`);
    break;
  default:
    console.log(`알 수 없는 명령: ${command}`);
    process.exit(1);
}

3. 정상적인 종료 처리

// graceful-shutdown.js
const express = require("express");
const app = express();
let server;

// Express 라우트 설정...

server = app.listen(3000, () => {
  console.log("서버가 3000 포트에서 실행 중입니다.");
});

// 정상 종료 함수
function gracefulShutdown() {
  console.log("정상 종료 시작...");
  server.close(() => {
    console.log("서버가 모든 연결을 종료했습니다.");

    // 데이터베이스 연결 종료 등의 정리 작업
    console.log("모든 정리 작업 완료. 종료합니다.");
    process.exit(0);
  });

  // 일정 시간 후에도 종료되지 않으면 강제 종료
  setTimeout(() => {
    console.error("정상 종료 시간 초과. 강제 종료합니다.");
    process.exit(1);
  }, 30000);
}

// SIGINT와 SIGTERM 신호 처리
process.on("SIGINT", gracefulShutdown);
process.on("SIGTERM", gracefulShutdown);

모범 사례

  1. 환경 변수 활용: 중요한 설정이나 민감한 정보는 코드에 하드코딩하지 말고 process.env를 통해 환경 변수로 관리합니다.

  2. 적절한 종료 코드 사용: 프로세스 종료 시 상황에 맞는 종료 코드를 제공합니다. 0은 성공, 0이 아닌 값은 오류를 나타냅니다.

  3. 정상 종료 구현: 특히 서버 애플리케이션에서는 SIGINT, SIGTERM 같은 시그널을 처리하여 연결을 정상적으로 종료하고 자원을 정리합니다.

  4. uncaughtException 신중히 사용: 이 이벤트는 마지막 수단으로만 사용하고, 가능한 한 개별 오류를 적절히 처리하는 것이 좋습니다.

  5. 플랫폼 독립적인 코드 작성: process.platform을 사용하여 필요한 경우에만 플랫폼별 코드를 작성합니다.

process 객체는 Node.js 애플리케이션의 런타임 환경과 직접 상호작용할 수 있는 강력한 인터페이스를 제공합니다. 적절하게 활용하면 더 안정적이고 효율적인 애플리케이션을 개발할 수 있습니다.

results matching ""

    No results matching ""