tenacity 사용하기

Tasker_Jang·6일 전

1. 기본 개념

tenacity함수 재시도 로직을 데코레이터로 선언하는 라이브러리입니다. 네트워크 호출처럼 일시적 실패가 잦은 코드에 try/except + for 루프를 직접 짜는 대신, 데코레이터 한 줄로 재시도 전략을 설정할 수 있습니다.


2. 임포트한 4개 함수 각각의 역할

from tenacity import (
    retry,                    # 데코레이터 본체 — 재시도 동작을 함수에 부착
    retry_if_exception_type,  # "어떤 예외일 때" 재시도할지 조건 설정
    stop_after_attempt,       # "몇 번까지" 재시도할지 제한
    wait_exponential,         # "얼마나 기다렸다가" 재시도할지 간격 설정
)

3. 실제 사용 코드 분해

@retry(
    retry=retry_if_exception_type((RateLimitError, APITimeoutError, APIConnectionError)),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    stop=stop_after_attempt(3),
    reraise=True,
)
def _call_api(messages, max_tokens):
    ...

retry=retry_if_exception_type(...)

retry_if_exception_type((RateLimitError, APITimeoutError, APIConnectionError))
# 이 세 가지 예외가 발생했을 때만 재시도
# 그 외 예외 (ValueError, KeyError 등)는 즉시 올림 — 재시도 없음

# RateLimitError    — API 호출 한도 초과
# APITimeoutError   — 30초 타임아웃 초과
# APIConnectionError — 네트워크 연결 실패

wait=wait_exponential(multiplier=1, min=2, max=10)

# 재시도 간격을 지수적으로 늘림
# multiplier=1, min=2, max=10 기준:

# 1회 실패 → 2초 대기
# 2회 실패 → 4초 대기
# 3회 실패 → 8초 대기 (max=10이므로 10초 상한)

# 계산식: min(multiplier * 2^attempt, max)
# = min(1 * 2^1, 10) = 2
# = min(1 * 2^2, 10) = 4
# = min(1 * 2^3, 10) = 8

stop=stop_after_attempt(3)

# 최대 3회 시도 후 중단
# 1회 실패 → 대기 → 2회 실패 → 대기 → 3회 실패 → 포기
# stop_after_attempt(3)은 "3번 시도" 기준 (재시도 횟수가 아님)

reraise=True

# 3회 모두 실패했을 때 원래 예외를 그대로 올림
# reraise=False(기본값)이면 tenacity 자체 예외(RetryError)로 감싸서 올림

# reraise=True  → raise RateLimitError(...)   ← 원래 예외 그대로
# reraise=False → raise RetryError(...)       ← tenacity 래퍼 예외

4. tenacity 없이 직접 구현한다면

# tenacity 없이 동일 로직을 직접 구현
import time

def _call_api_manual(messages, max_tokens):
    max_attempts = 3
    wait = 2

    for attempt in range(1, max_attempts + 1):
        try:
            response = client.chat.completions.create(...)
            return response.choices[0].message.content
        except (RateLimitError, APITimeoutError, APIConnectionError) as e:
            if attempt == max_attempts:
                raise   # 마지막 시도면 그냥 올림
            time.sleep(wait)
            wait = min(wait * 2, 10)  # 지수 증가
        # 그 외 예외는 except에 안 걸려서 즉시 올라감

# tenacity @retry 데코레이터가 위 로직을 대체

5. 핵심 요약

파라미터역할이 코드에서 설정값
retry재시도 조건Rate/Timeout/Connection 에러 3종
wait재시도 간격2s → 4s → 8s (지수 증가)
stop최대 시도 횟수3회
reraise실패 시 예외 타입원래 예외 그대로

한 줄 요약: tenacity@retry 데코레이터는 지정한 예외 발생 시 exponential backoff 간격으로 최대 N회 재시도하는 로직을 선언적으로 표현하며, try/except + for 루프를 직접 짜는 것보다 간결하고 오류가 적습니다.

profile
ML Engineer 🧠 | AI 모델 개발과 최적화 경험을 기록하며 성장하는 개발자 🚀 The light that burns twice as bright burns half as long ✨

0개의 댓글