Python requests 재시도: 백오프·Retry-After·POST

Requests는 기본적으로 재시도하지 않습니다. urllib3 Retry(백오프, status_forcelist)를 Session에 마운트하고, POST는 Idempotency-Key가 있을 때만 재시도하세요.

읽는 시간 5분Sume
전체 글

Python Requests에서 재시도하려면 Session에 HTTPAdapter(max_retries=Retry(...))를 마운트하세요. urllib3의 Retry가 재시도 횟수, 재시도를 강제할 상태 코드(status_forcelist), 백오프 시간(backoff_factor)을 정하며, 기본적으로 Retry-After를 따릅니다. Requests는 실패한 연결을 스스로 재시도하지 않고, Retry의 기본 메서드에는 POST가 빠져 있습니다. POST는 모든 POST에 Idempotency-Key가 있을 때만 추가하세요. 그래야 다시 보낸 생성 요청이 두 번 과금하는 대신 원래 실행을 돌려줍니다.

Requests 관련 내용은 고급 사용법과 개발자 인터페이스 페이지에서, urllib3 관련 내용은 urllib3.util 레퍼런스에서, Tenacity 관련 내용은 Tenacity 문서에서, Sume 관련 내용은 Format 호출하기 (영문), 오류와 비용 (영문), 오류와 요청 한도 (영문), 인증에서 가져왔습니다. 모두 2026-09-28에 확인했습니다. 호출은 HTTPS를 직접 쓰며, Sume 플러그인은 쓰지 않습니다.

requests Session에 재시도를 어떻게 추가하나요?

Retry를 하나 만들어 HTTPAdapter로 감싸고, 어댑터를 https:// 접두사에 마운트하세요. 그러면 그 세션을 거치는 모든 요청이 이 정책을 따릅니다. 아래 예제는 429, 500, 502, 503, 504를 백오프와 지터를 적용해 재시도하며, POST를 포함한 이유는 오직 모든 생성 요청이 Idempotency-Key를 보내기 때문입니다. Requests는 직접 설정하지 않으면 타임아웃이 없으므로, 모든 호출에 timeout=도 함께 넘기세요.

import os
import requests
from requests.adapters import HTTPAdapter
from urllib3.util import Retry

retry = Retry(
    total=4,
    backoff_factor=1,
    backoff_jitter=0.5,
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods={"GET", "HEAD", "POST"},  # POST only because every POST sends a key
    raise_on_status=False,  # return the last response instead of raising
)
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retry))
session.headers.update({"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"})

resp = session.post(
    "https://api.sume.com/v1/formats/acme/weekly-promo/runs",
    json={"input": {"week": "2026-W40"}},
    headers={"Idempotency-Key": "weekly-promo-2026-W40"},
    timeout=(3.05, 30),
)
resp.raise_for_status()
run = resp.json()["data"]  # 202: new run. 200: replay, idempotency_hit is true.

어떤 Retry 설정이 중요하고, 기본값은 무엇인가요?

기본값인 respect_retry_after_header=True에서는 Retry-After가 담긴 413, 429, 503이 재시도를 일으키고, 대기 시간은 그 헤더를 따릅니다. Sume는 429에 이 헤더를 초 단위로 보냅니다. 나머지는 모두 backoff_factor에 따라 기다립니다.

urllib3 2.8.0의 urllib3.util 레퍼런스 기준, 2026-09-28 확인.
설정기본값역할
total10허용되는 전체 재시도 횟수. 다른 횟수 설정보다 우선함
allowed_methodsDELETE, GET, HEAD, OPTIONS, PUT, TRACE재시도하는 메서드. POST는 기본 집합에 없음
status_forcelistNoneallowed_methods에 있는 메서드의 재시도를 강제하는 상태 코드
backoff_factor0, 백오프 없음factor × 2^(이전 재시도 횟수)만큼 대기. 0.1이면 0.0, 0.2, 0.4, 0.8초 …
backoff_max120한 번에 대기하는 최대 시간(초)
backoff_jitter0.0대기할 때마다 0초에서 n초 사이의 무작위 시간을 더함
respect_retry_after_headerTrue413, 429, 503의 Retry-After를 따름
raise_on_statusTrue상태 코드 재시도를 다 쓰면 마지막 응답을 반환하지 않고 예외를 발생시킴

urllib3 Retry로 POST를 재시도해도 되나요?

서버가 그 요청을 두 번 실행할 수 없을 때만 됩니다. 연결 오류는 요청을 보내기 전에 일어나지만, 읽기 오류는 요청이 서버로 전송된 뒤에 일어나며, urllib3 문서는 그런 요청에 부수 효과가 있을 수 있다고 경고합니다. 유료 생성 요청이라면 이미 실행 중일 수 있습니다. Requests의 자체 재시도 예제는 POST를 allowed_methods에 넣지만, 모든 POST에 Idempotency-Key가 있을 때만 그대로 따라 하세요. Sume 문서는 안전하지 않은 제출 요청을 키 없이 재시도하지 말라고 안내하기 때문입니다. 키가 있으면 같은 키와 본문은 두 번째 청구 없이 200과 원래 실행을 받습니다. 그 밖의 재전송 응답은 AI 영상 API 멱등성 키에 정리되어 있습니다. Retry 설정을 좌우하는 경우는 두 가지입니다.

  • 읽기 타임아웃 뒤의 재시도는 첫 요청이 아직 처리 중일 때 Sume에 도착해 409 idempotency_key_in_use를 받을 수 있으며, 이 응답은 약 일 초 뒤에 재시도할 수 있습니다. 그래도 409는 status_forcelist에 넣지 마세요. 409는 키가 다른 본문과 함께 재사용된 idempotency_conflict도 뜻하며, 이 경우는 그대로 재시도하면 안 됩니다.
  • 타임아웃은 여러분의 대기를 끝낼 뿐, 작업을 끝내지는 않습니다. 타임아웃된 생성 요청이 이미 실행을 시작했을 수 있으며, Sume 문서는 폴링 루프를 포기해도 실행이나 그 비용이 멈추지 않는다고 말합니다. POST가 allowed_methods에 있으면 Retry는 같은 키와 본문으로 생성 요청을 다시 보내고, Sume는 새 실행을 시작하는 대신 그 실행을 돌려줍니다.

어떤 오류는 재시도하면 안 되나요?

그 밖의 4xx 대부분입니다. 생성 단계의 4xx는 아무것도 실행되지 않았고 아무것도 청구되지 않았다는 뜻이므로 호출을 고치세요. status_forcelist는 상태 코드만 보므로, next_action이 fix_input인 Sume의 502 attachment_fetch_failed도 다시 보냅니다. 이 점이 중요하다면 retryable과 retry_after_seconds가 담긴 오류 봉투를 보고 여러분의 코드에서 판단하세요. Node에서 쓰는 이 패턴은 Axios retry: 멱등성 키로 POST 안전하게 재시도하기에서 보여 줍니다.

Tenacity는 어떤가요?

Tenacity는 HTTP 요청이 아니라 Python 함수를 재시도합니다. 인수 없이 쓴 @retry는 기다리지 않고 끝없이 재시도하므로, @retry(stop=stop_after_attempt(5), wait=wait_random_exponential(multiplier=1, max=60))처럼 중단 조건과 대기 방식을 항상 지정하세요. Tenacity는 함수가 보내는 것을 그대로 다시 보내므로 POST 규칙도 같습니다. 같은 키, 같은 본문입니다.

출처

관련 글

연동 카테고리의 다른 글

연동 글 전체 보기

작성자 Sume