IT

Python requests 재시도 로직, API 장애와 네트워크 불안정성을 해결하는 설계 패턴

AI 자동화 실무 2026. 8. 4. 15:21
SMALL

네트워크 통신에서 발생하는 일시적인 오류를 극복하려면 단순히 예외 처리를 하는 수준을 넘어, 체계적인 재시도(Retry) 설계가 반드시 필요합니다. Python의 requests 라이브러리는 기본적으로 재시도 기능을 내장하고 있지 않지만, urllib3의 Retry 클래스와 HTTPAdapter를 결합하면 코드 몇 줄로 강력한 복구 로직을 구축할 수 있습니다.

실무에서 API를 연동하다 보면 서버의 일시적인 과부하나 찰나의 네트워크 끊김으로 인해 요청이 실패하는 경우가 빈번합니다. 이때 무작정 다시 요청을 보내는 것이 아니라, 서버에 가해지는 부담을 고려하면서도 성공 확률을 높이는 전략적 접근이 중요합니다.

단순히 루프를 돌려 재시도하는 방식은 코드가 지저분해질 뿐만 아니라, 무한 루프나 리소스 낭비 같은 부작용을 낳기 쉽습니다. 따라서 표준화된 라이브러리 기능을 활용해 재시도 횟수, 간격, 대상 상태 코드를 명확히 정의하는 것이 유지보수 측면에서도 유리합니다.

본격적인 구현에 앞서 파이썬을 활용한 HTTP 통신의 기본 구조와 타임아웃 설정의 중요성을 먼저 이해하고 있다면, 이번 글에서 다루는 재시도 설계 패턴을 실무 프로젝트에 훨씬 더 유연하게 적용할 수 있을 것입니다.

Python requests 재시도 대표 이미지
Python requests 재시도 주제를 읽기 전에 먼저 보면 좋은 대표 이미지 · 핵심 포인트: 왜 필요한지, 재시도 기준, 백오프

핵심 내용 먼저 보기

핵심 키워드 Python requests 재시도 · 연관 검색어 Python requests 재시도, HTTPAdapter Retry, 지수 백오프, API 안정성, 파이썬 네트워크 프로그래밍

왜 단순 try-except 문으로는 부족할까?

많은 개발자가 API 호출 실패를 대비해 try-except 구문 안에 requests.get()을 넣고 루프를 돌리는 방식을 선택합니다. 하지만 이 방식은 지수 백오프(Exponential Backoff)나 특정 HTTP 상태 코드에 따른 분기 처리를 구현하기 시작하면 코드가 급격히 복잡해집니다.

또한, 모든 에러에 대해 재시도하는 것은 위험합니다. 예를 들어 404 Not Found나 401 Unauthorized 같은 에러는 다시 시도한다고 해결될 문제가 아니기 때문입니다. 반면 503 Service Unavailable이나 429 Too Many Requests는 잠시 기다린 후 다시 시도하면 성공할 가능성이 높습니다. 이러한 세밀한 제어를 직접 구현하는 대신 검증된 라이브러리 기능을 사용하는 것이 실수를 줄이는 지름길입니다.

HTTPAdapter와 Retry 클래스를 활용한 표준 구현

requests 라이브러리에서 재시도를 구현하는 가장 깔끔한 방법은 urllib3.util.retry.Retry 클래스를 사용하는 것입니다. 이 클래스를 생성한 뒤 requests.Session 객체의 mount 메서드를 통해 특정 URL 패턴에 적용할 수 있습니다.

핵심 파라미터인 total은 최대 재시도 횟수를, backoff_factor는 재시도 간격을 결정합니다. 예를 들어 backoff_factor를 1로 설정하면 1초, 2초, 4초 순으로 대기 시간이 늘어납니다. 또한 status_forcelist를 통해 500, 502, 503, 504 등 재시도가 필요한 상태 코드를 명시적으로 지정할 수 있어 불필요한 요청을 방지합니다.

실무에서 자주 범하는 재시도 설계의 실수

가장 흔한 실수는 재시도 횟수를 너무 크게 잡거나 대기 시간 없이 즉시 재시도하는 것입니다. 이는 장애가 발생한 서버에 'DDoS 공격'과 다름없는 부하를 주어 상황을 악화시킵니다. 반드시 지수 백오프를 적용하여 서버가 회복할 시간을 주어야 합니다.

또 다른 판단 포인트는 POST 요청에 대한 재시도 여부입니다. GET 요청은 여러 번 수행해도 결과가 변하지 않는 멱등성(Idempotency)을 가지지만, 결제나 데이터 생성과 관련된 POST 요청은 중복 처리가 발생할 위험이 있습니다. 따라서 POST 요청에 재시도를 적용할 때는 서버 측에서 중복 요청을 걸러낼 수 있는 멱등성 키(Idempotency Key)가 있는지 반드시 확인해야 합니다.

안정적인 운영을 위한 로깅과 모니터링

재시도 로직이 작동하고 있다는 것은 시스템 어딘가에 불안정 요소가 있다는 신호입니다. 단순히 재시도가 성공했다고 해서 방치하면 안 되며, 몇 번의 시도 끝에 성공했는지 혹은 결국 실패했는지를 로깅해야 합니다. 이를 통해 특정 API의 응답 속도가 느려지거나 에러율이 높아지는 징후를 조기에 포착할 수 있습니다.

이후에는 비동기 환경에서의 재시도 처리를 위해 aiohttp나 httpx 같은 라이브러리의 재시도 패턴을 살펴보는 것도 좋습니다. 또한, 대규모 트래픽을 다루는 환경이라면 서킷 브레이커(Circuit Breaker) 패턴을 도입해 장애가 전파되는 것을 원천 차단하는 전략으로 확장해 나가는 흐름이 자연스럽습니다.

결국 Python requests 재시도 설계의 핵심은 '언제, 얼마나, 어떻게' 다시 시도할 것인가를 명확히 정의하는 데 있습니다. 무조건적인 반복보다는 서버의 상태를 존중하며 영리하게 기다리는 코드가 좋은 코드입니다.

오늘 살펴본 Retry 클래스와 HTTPAdapter 조합은 대부분의 실무 환경에서 충분히 강력한 성능을 발휘합니다. 다만 프로젝트의 성격에 따라 타임아웃 값과 백오프 계수를 미세하게 조정하며 최적의 지점을 찾아가는 과정이 필요합니다.

안정적인 네트워크 통신을 구축했다면, 다음 단계로는 대량의 요청을 효율적으로 처리하기 위한 비동기 프로그래밍이나 API 응답 캐싱 전략을 고민해 보시는 것을 추천합니다.

자주 묻는 질문

재시도 횟수는 보통 몇 회가 적당한가요?

일반적인 외부 API 연동 시에는 3회에서 5회 사이를 권장합니다. 너무 적으면 일시적인 장애를 극복하기 어렵고, 너무 많으면 전체 시스템의 응답 시간이 길어지는 부작용이 있습니다.

429 Too Many Requests 에러도 재시도해야 하나요?

네, 429 에러는 재시도가 필요한 대표적인 케이스입니다. 다만 이때는 Retry-After 헤더 값을 확인하여 서버가 지정한 시간만큼 대기한 후 요청을 보내는 것이 매너입니다.

Timeout 설정과 Retry 설정 중 무엇이 더 중요한가요?

둘 다 중요합니다. Timeout이 설정되어 있지 않으면 재시도 로직 자체가 시작되지 못하고 무한 대기에 빠질 수 있습니다. 항상 connect와 read 타임아웃을 먼저 설정한 뒤 재시도 로직을 얹어야 합니다.


해시태그

#Pythonrequests재시도 #HTTPAdapterRetry #지수백오프 #API안정성 #파이썬네트워크프로그래밍 #urllib3Retry설정

LIST