Python API 호출이 멈출 때는 재시도 횟수보다 timeout을 먼저 지정해야 합니다. 그다음 연결 오류인지, rate-limit·서버 오류 응답인지, 같은 요청을 다시 보내도 안전한지 구분해야 합니다. GET은 제한된 재시도를 적용하기 쉽지만 POST는 중복 실행 가능성을 먼저 확인합니다.
timeout은 연결과 응답 대기를 제한합니다
urllib.request.urlopen()에는 timeout 인자를 지정할 수 있습니다. Requests도 요청별 timeout을 생략하지 않는 편이 안전합니다. timeout은 클라이언트가 연결이나 응답을 무한정 기다리지 않게 하는 경계입니다.
from urllib.request import Request, urlopen
request = Request("https://example.com/health", method="GET")
with urlopen(request, timeout=timeout_seconds) as response:
body = response.read()
위 코드는 외부 API를 호출한 결과가 아니라 timeout을 지정하는 형태를 보여주는 예시입니다.
모든 오류를 같은 방식으로 재시도하지 않습니다
Requests 공식 문서는 ConnectTimeout을 연결을 수락하지 못한 상황으로 설명하며 재시도에 안전한 예외로 구분합니다. 인증 오류나 잘못된 요청처럼 입력을 고쳐야 하는 오류는 재시도로 해결되지 않습니다.
rate-limit 응답은 호출이 너무 많다는 뜻이므로 서버가 안내한 대기 시간이 있으면 그 값을 우선 확인합니다. 서버 오류는 일시적일 수 있지만 항상 그런 것은 아니므로 backoff와 상한을 둡니다.
재시도 조건을 분리해 설정합니다
urllib 계열의 Retry 설정은 timeout, 상태 코드, 허용 메서드, backoff를 나누어 설정할 수 있습니다. 읽기 전용 GET만 제한적으로 재시도하려면 허용 메서드에 GET만 두는 식으로 범위를 좁힐 수 있습니다. 이 설정은 성공을 보장하지 않으므로 오류별 상한과 Retry-After 처리 방식을 API 정책에 맞춰 정해야 합니다.
POST는 중복 실행 가능성을 먼저 확인합니다
POST는 서버 상태를 바꾸는 작업일 수 있습니다. 연결이 끊겼을 때 서버가 이미 작업을 끝냈는지 모를 수 있으므로 같은 POST를 반복하면 중복 생성이 생길 수 있습니다. API가 idempotency key를 제공하면 사용하고, 그렇지 않으면 실패 로그를 남긴 뒤 상태 조회나 수동 확인을 거치는 편이 안전합니다.
실행 전 체크 순서
- 요청별 connect/read timeout을 지정합니다.
- 인증·입력 오류처럼 재시도해도 바뀌지 않는 오류를 제외합니다.
- 재시도 대상 상태 코드와 최대 횟수, backoff를 정합니다.
- GET인지 POST인지 확인하고 POST라면 중복 실행 방지 방법을 확인합니다.
- 상한에 도달하면 실패 원인을 기록하고 다음 자동화 단계로 넘기지 않습니다.
API별 최종 값은 해당 API 문서를 기준으로 정하세요.
이 글의 기준은 무조건 다시 보내는 것이 아니라, 멈춤을 제한하고 중복 실행을 피하면서 실패 원인별로 다음 행동을 고르는 것입니다. timeout이 없으면 멈춘 작업과 느린 작업을 구분하기 어렵고, 재시도 조건이 없으면 일시적 오류가 영구 실패나 중복 실행으로 이어질 수 있습니다. GET처럼 반복해도 상태 변경이 없는 요청과 POST처럼 서버 상태를 바꿀 수 있는 요청을 같은 정책으로 재시도하지 않습니다. 다음에는 API별 Retry-After와 idempotency key 지원 여부를 확인한 뒤 재시도 상한을 정하세요.