Set a request timeout

느리거나 응답 없는 서버에 무한정 매달리지 않도록 요청에 타임아웃을 거는 레시피입니다. 기본값은 대부분 무한대라 반드시 명시해야 합니다.

개요

느리거나 응답 없는 서버에 무한정 매달리지 않도록 요청에 타임아웃을 거는 레시피입니다. 기본값은 대부분 무한대라 반드시 명시해야 합니다.

코드로 보기

# cap the whole transfer and the connect phase separately:
curl --max-time 10 --connect-timeout 3 https://api.example.com/slow
// AbortController + timeout (or AbortSignal.timeout(ms)):
const ctrl = new AbortController();
const id = setTimeout(() => ctrl.abort(), 5000);
try {
  const res = await fetch('https://api.example.com/slow', { signal: ctrl.signal });
  return await res.json();
} finally {
  clearTimeout(id);
}
import requests

# (connect timeout, read timeout) in seconds
try:
    res = requests.get('https://api.example.com/slow', timeout=(3, 10))
except requests.Timeout:
    print('request timed out')

설명

타임아웃은 두 단계로 나눠 생각하세요. 연결 수립까지의 시간(`--connect-timeout`, requests 튜플의 첫 값)과 전체 전송 시간(`--max-time`, requests 튜플의 둘째 값=읽기 타임아웃)입니다. 연결은 빨리 실패시키고 본문 수신은 조금 넉넉히 주는 식으로 나누면 유용합니다.

브라우저 `fetch`는 옵션형 타임아웃이 없으므로 `AbortController`로 직접 구현하거나 최신 환경에서 `AbortSignal.timeout(ms)`를 씁니다. 타임아웃이 걸리면 `AbortError`가 던져지니 이를 잡아 재시도·폴백으로 연결하세요.

타임아웃과 재시도를 함께 쓸 때는 주의가 필요합니다. 요청이 실제로 서버에 도달해 처리되는 중에 클라이언트만 타임아웃될 수 있어, 비멱등 요청(POST)을 그냥 재시도하면 중복이 생깁니다. 이럴 땐 `Idempotency-Key`를 쓰거나 재시도 대상을 멱등 요청으로 제한하세요. 서버가 자체적으로 대기 시간을 초과하면 408·504가 반환되기도 합니다.

관련 헤더

관련 상태코드