빠른 설정
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200);
res.end("ok");
});
server.requestTimeout = 30_000; // 요청 전체 최대 시간
server.headersTimeout = 10_000; // 헤더 수신 제한
server.keepAliveTimeout = 5_000; // 유휴 연결 재사용 대기
server.listen(3000);
process.on("SIGTERM", () => {
server.close(() => process.exit(0)); // 새 연결 중단, 기존 요청 완료 대기
server.closeAllConnections(); // keep-alive 연결 즉시 해제 (Node 18.2+)
setTimeout(() => process.exit(1), 10_000); // 강제 종료 안전망
});연결 관리
먼저 구분해 둘 기본형은 아래입니다.
- 요청 전체 제한:
requestTimeout - 헤더 수신 제한:
headersTimeout - 유휴 keep-alive 제한:
keepAliveTimeout - 새 연결 차단:
server.close() - 남은 연결 정리:
closeAllConnections(), 필요 시closeIdleConnections()
requestTimeout
요청 전체가 끝나기까지 허용할 최대 시간입니다. 느린 업로드나 슬로우 클라이언트 방어 기준으로 봅니다.
headersTimeout
헤더만 질질 보내는 연결을 빨리 잘라내는 값입니다. 보통 requestTimeout보다 짧게 둡니다.
keepAliveTimeout
응답을 보낸 뒤 다음 요청을 기다리는 유휴 시간입니다. 짧으면 재사용 이점이 줄고, 길면 종료 시 프로세스가 오래 남습니다.
즉:
- 요청 자체가 너무 오래 간다:
requestTimeout - 헤더만 늦다:
headersTimeout - 응답 뒤 연결이 너무 오래 남는다:
keepAliveTimeout
종료 시 가장 먼저 보는 문제는 keep-alive다
server.close()는 새 연결만 막고 기존 연결은 기다립니다. 그런데 keep-alive 유휴 연결은 요청이 없어도 살아 있으니, 종료 콜백이 생각보다 늦게 옵니다. 배포 중 "서버가 안 죽는다"는 문제는 이 지점이 많습니다.
Node 18.2+라면 server.closeAllConnections()를 같이 써서 유휴 연결을 정리하는 편이 운영상 훨씬 단순합니다.
process.on("SIGTERM", () => {
server.close(() => process.exit(0));
server.closeAllConnections();
});반대로 server.close()만 호출하고 keep-alive 연결을 그대로 두면, "종료 중인데 왜 프로세스가 계속 살아 있지?"라는 상황이 생기기 쉽습니다.
종료는 신호 처리보다 순서 고정이 중요하다
SIGTERM을 받았다고 바로 process.exit() 해 버리면 응답 중인 요청, 로그 flush, DB 정리가 중간에 잘릴 수 있습니다.
그래서 shutdown 카드는 "무슨 시그널을 받는가"보다 "새 연결 차단 -> 연결 정리 -> 리소스 정리 -> 종료" 순서를 고정하는 카드에 가깝습니다.
종료 순서를 코드로 고정한다
실전에서는 아래 순서를 기억하면 됩니다.
- SIGTERM 수신
- 새 연결 차단
- keep-alive 연결 정리
- DB, 큐, 로그 플러시 같은 리소스 정리
- 안전망 타이머 안에 종료
종료 로직이 여러 파일에 흩어져 있으면 누락되기 쉬우니 한 함수로 모으는 편이 낫습니다.
어디서 끊을까
체크포인트
- 느린 요청 제한:
requestTimeout - 헤더만 느린 연결 제한:
headersTimeout - 유휴 연결 재사용 시간:
keepAliveTimeout - 새 연결 차단:
server.close() - keep-alive 정리:
server.closeAllConnections() - idle 연결만 먼저 정리한다:
server.closeIdleConnections() - 종료 안전망:
setTimeout(...).unref()
주의할 점
server.close()만 호출하고 끝내면 keep-alive 때문에 종료가 길어질 수 있다. 배포 환경에서는 closeAllConnections()와 강제 종료 안전망을 같이 두는 편이 낫다.
참고 링크
2 sources