429 Too Many Requests(속도 제한) 응답을 만났을 때 잠시 기다렸다가 지수 백오프로 재시도하는 레시피입니다.
429 Too Many Requests(속도 제한) 응답을 만났을 때 잠시 기다렸다가 지수 백오프로 재시도하는 레시피입니다.
# curl's built-in retry honors Retry-After on 429/503:
curl --retry 5 --retry-delay 1 --retry-max-time 60 \
--retry-all-errors https://api.example.com/dataasync function withRetry(url, opts = {}, max = 5) {
for (let i = 0; i < max; i++) {
const res = await fetch(url, opts);
if (res.status !== 429) return res;
const ra = res.headers.get('Retry-After');
const waitMs = ra ? Number(ra) * 1000
: Math.min(2 ** i * 1000, 30000);
const jitter = Math.random() * 250;
await new Promise(r => setTimeout(r, waitMs + jitter));
}
throw new Error('rate limited: retries exhausted');
}import time, random, requests
def get_with_retry(url, tries=5):
for i in range(tries):
r = requests.get(url)
if r.status_code != 429:
return r
ra = r.headers.get('Retry-After')
wait = float(ra) if ra else min(2 ** i, 30)
time.sleep(wait + random.uniform(0, 0.25)) # jitter
raise RuntimeError('rate limited')가장 먼저 `Retry-After` 헤더를 확인하세요. 서버가 초 단위 숫자나 HTTP-date로 다시 시도해도 되는 시점을 알려줍니다. 이 값이 있으면 그대로 따르는 것이 가장 정확하고, 없으면 스스로 백오프를 계산합니다.
재시도 간격은 지수 백오프(1s, 2s, 4s, 8s…)로 늘리되, 반드시 무작위 지터(jitter)를 더하세요. 지터가 없으면 제한에 걸린 모든 클라이언트가 동시에 재시도해 서버를 다시 몰아치는 'thundering herd'가 발생합니다. 최대 대기 시간에는 상한(예: 30초)을 두세요.
429뿐 아니라 503 Service Unavailable도 같은 백오프 전략을 쓰는 것이 좋습니다. 다만 POST 같은 비멱등 요청은 무작정 재시도하면 중복 처리 위험이 있으니, `Idempotency-Key`가 있거나 안전이 보장될 때만 재시도하세요. 많은 API는 `X-RateLimit-Remaining`·`X-RateLimit-Reset`로 남은 한도를 미리 알려줍니다.