본문 바로가기
Q&A해결2026년 8월 12일1분 읽기

Node 18로 올린 뒤부터 오래 걸리는 요청이 중간에 뚝 끊기고 408이 뜹니다

t
timeout_daeun
조회 440댓글 1

Node 16에서 18로 런타임 올린 뒤로 이상한 현상이 생겼어요. 리포트 생성처럼 처리에 시간이 좀 걸리는 API(길면 2~3분)가 완료되기 전에 커넥션이 끊깁니다. 클라이언트는 socket hang up, 서버 접근 로그엔 408이 찍혀요.

코드는 하나도 안 바꿨고 딱 Node 버전만 올렸는데 이렇게 됐습니다. 로드밸런서 타임아웃도 넉넉하게 잡혀 있고요. 예전엔 잘 되던 긴 요청이 왜 갑자기 끊길까요?

댓글 1

김김영삼2개월 전
코드 안 바꿨는데 Node 버전만 올리고 나서 긴 요청이 끊긴다면, 십중팔구 HTTP 서버 타임아웃 기본값 변경 때문이에요. 예전 Node는 server.requestTimeout 기본값이 0(무제한)이었는데, 중간 버전대부터 보안상 이유(Slowloris 같은 저속 공격 방어)로 기본 requestTimeout이 켜졌습니다. 그래서 하나의 요청이 그 시간을 넘기면 서버가 408을 내면서 소켓을 끊어버려요. 3분짜리 요청이 이 한도에 걸린 겁니다.

관련해서 두 개를 같이 조정하면 됩니다. server를 만든 다음에 이렇게요.

const server = app.listen(PORT)
server.requestTimeout = 5 * 60 * 1000 // 요청 전체 허용 시간
server.headersTimeout = 60 * 1000 // 헤더 다 받는 데까지 허용 시간

requestTimeout은 요청 시작부터 끝까지 전체 허용 시간이라 이걸 넉넉히(예: 5분) 늘리면 긴 API가 안 끊깁니다. headersTimeout은 헤더 수신까지의 시간이라 이건 오히려 짧게 유지하는 게 공격 방어에 좋아요. 둘의 역할이 다르니 requestTimeout만 올리세요.

다만 진짜 권하고 싶은 건, 2~3분 걸리는 걸 HTTP 요청 하나로 붙잡고 있는 구조 자체를 다시 보는 거예요. 그 방식은 이 타임아웃뿐 아니라 앞단 로드밸런서/프록시 타임아웃, 클라이언트 재시도, 배포 중 연결 끊김 등 깨질 지점이 너무 많습니다. 리포트 생성 같은 건 요청 받으면 즉시 202로 작업 ID를 돌려주고 백그라운드 잡으로 돌린 다음, 클라이언트가 상태를 폴링하거나 완료되면 알림(웹훅/SSE) 받는 비동기 패턴으로 바꾸는 게 정석이에요. 당장은 requestTimeout 늘려 급한 불 끄고, 여유 되면 잡 큐로 빼는 걸 로드맵에 넣으시길.

참고로 이 타임아웃들은 Nginx 뒤에 있으면 Nginx의 proxy_read_timeout하고도 같이 봐야 해요. 둘 중 짧은 쪽이 먼저 끊으니, Node만 늘리고 Nginx가 짧으면 여전히 끊깁니다.
Ctrl+Enter로 등록