-
Notifications
You must be signed in to change notification settings - Fork 0
Description
📝 node.js에서 graceful shutdown 적용하기
📚 주제:
- graceful shutdown이란 무엇인가
- 왜 적용해야 할까?
- 실제 node.js 서버에서의 구현 예시
- next.js에서의 적용
📖 핵심 내용:
❓ Graceful Shutdown이란?
애플리케이션이나 서버가 종료될 때, 실행 중인 작업을 안전하게 처리하고 리소스를 정리하며 종료하는 과정을 말합니다. 이는 단순히 강제로 프로세스를 종료하는 것과는 달리, 시스템이 정상적인 상태에서 종료되도록 도와줍니다.
❔ Graceful Shutdown의 필요성
- 데이터 손실 방지: 실행 중인 요청이나 트랜잭션이 갑작스럽게 중단되면 데이터가 손실되거나 손상될 수 있습니다. Graceful Shutdown은 이를 방지합니다.
- 일관성 유지: 애플리케이션이 예상치 못한 종료로 인해 시스템 상태가 불일치하게 되는 것을 방지합니다.
- 리소스 정리: 파일, 데이터베이스 연결, 네트워크 소켓 등 사용 중인 리소스를 정리하여 메모리 누수나 리소스 잠금을 방지합니다.
- 사용자 경험 향상: 서비스가 종료되더라도 사용자 요청을 가능한 한 마무리하여 부정적인 영향을 최소화합니다.
🏗️ Graceful Shutdown의 작동 방식
- 종료 신호 수신:
- 운영 체제에서 종료 신호(SIGTERM, SIGINT 등)를 받습니다.
- 새 작업 수락 중단:
- 새 요청을 수락하지 않고, 기존 요청 처리에 집중합니다.
- 예를 들어, 웹 서버는 더 이상 클라이언트 요청을 받지 않습니다.
- 기존 작업 완료:
- 현재 진행 중인 작업(예: 데이터 저장, 파일 처리, API 응답 등)을 완료합니다.
- 제한 시간을 두어 너무 오래 걸리지 않도록 설정할 수도 있습니다.
- 리소스 정리:
- 열려 있는 파일, 데이터베이스 연결, 네트워크 소켓 등을 닫습니다.
- 캐시나 임시 데이터를 정리합니다.
- 프로세스 종료:
- 모든 작업이 완료되면 프로세스를 안전하게 종료합니다.
Node.js 기반의 Express 서버 구현 예시 코드
const express = require('express');
const app = express();
let server;
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 서버 시작
server = app.listen(3000, () => {
console.log('Server is running on port 3000');
});
// Graceful Shutdown 구현
process.on('SIGTERM', () => {
console.log('SIGTERM signal received: closing HTTP server');
server.close(() => {
console.log('HTTP server closed');
// 추가적인 리소스 정리 작업 (예: DB 연결 종료)
process.exit(0);
});
});
process.on('SIGINT', () => {
console.log('SIGINT signal received: closing HTTP server');
server.close(() => {
console.log('HTTP server closed');
process.exit(0);
});
});next.js에서 적용하기
#8 에서 작성한 server.js 에 graceful shutdown 코드를 추가하였다.
//server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const v8 = require('v8');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const activeConnections = new Set(); // 활성 연결을 추적하기 위한 Set
app.prepare().then(() => {
const server = createServer((req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
});
console.log(`App started with PID: ${process.pid}`);
server.listen(3000, (err) => {
if (err) throw err;
console.log('> Ready on frontend server');
});
// 활성 연결 추적
server.on('connection', (socket) => {
activeConnections.add(socket);
socket.on('close', () => {
activeConnections.delete(socket);
});
});
// Graceful shutdown 처리
process.on('SIGTERM', async () => {
console.log('SIGTERM received. Closing server...');
server.close(() => {
console.log('Server closed. Closing active connections...');
// 모든 활성 연결 강제 종료
activeConnections.forEach((socket) => socket.destroy());
setTimeout(() => {
console.log('Shutdown after sleep.');
process.exit(0); // 정상 종료
}, 70000);
});
});
// SIGINT 처리 (Ctrl+C)
process.on('SIGINT', () => {
console.log('SIGINT received. Performing graceful shutdown...');
server.close(() => {
console.log('Server closed.');
process.exit(0); // 정상 종료
});
});
});
// 종료 시 code 출력
process.on('exit', (code) => {
console.log(`Process exited with code: ${code}`);
});
SIGTERM 발생을 위한 종료 명령어
ps aux | grep node해당 명령어를 통해 PID를 알아낸다.
kill -SIGTERM [PID]알아낸 PID을 kill.
🔥 SIGINT 신호는 인식하나, SIGTERM은 인식하지 못하는 현상

로컬에서 위의 명령어를 통해 SIGTERM kill을 시도했으나 SIGTERM 로그가 남지 않고 143 코드를 남기며 종료 되었다.

SIGINT (ctrl+c)를 통한 kill의 경우에는 의도한 바 대로 로그를 남기며 정상 종료되었다.
👩🏻🚒 왜 SIGTERM 신호는 인식하지 못하는가?
- stack overflow와 node.js 깃헙 이슈 답에 따르면 window환경에서 unix 스타일의 신호 (SIGTERM, SIGNUP등)를 기본적으로 지원하지 않아, Node.js에서 이런 신호를 수신하거나 처리하는 것이 제한적입니다.
- Node.js는 Windows에서 process.kill() 및 ChildProcess.kill() 메서드를 통해 일부 신호를 에뮬레이트합니다. 그러나 이는 완전한 신호 지원이 아니며, 특정 신호(SIGTERM, SIGHUP 등)는 Windows에서 지원되지 않습니다.
👩🏻🚒 mac OS에서 테스트 - 성공
💡 참고 자료:
https://www.ryuollojy.com/articles/nodejs-graceful-shutdown
vercel/next.js#19693
https://velog.io/@hwisaac/NextJS-Depoyment#%EC%88%98%EB%8F%99-graceful-shutdown
vercel/next.js#60059
https://nextjs-ko.org/docs/app/building-your-application/deploying#manual-graceful-shutdowns
https://dtrunin.github.io/2022/04/05/nodejs-graceful-shutdown.html
https://stackoverflow.com/questions/63241807/nodejs-process-kill-doesnt-seem-to-work-on-windows-when-i-try-to-programaticall
https://stackoverflow.com/questions/63241807/nodejs-process-kill-doesnt-seem-to-work-on-windows-when-i-try-to-programaticall



