재시도 (Retry)

@retry 데코레이터는 선택한 예외가 발생하거나 선택한 HTTP 상태가 반환되면, 시도 사이의 대기 시간을 늘려 가며 요청을 자동으로 재시도합니다. @AsyncSession.single_session 또는 훅 데코레이터와 마찬가지로 요청 메서드에 적용합니다.

재시도 예제
 1from typing import Annotated, Any
 2
 3from ahttp_client import (
 4    AsyncSession,
 5    HTTPServerError,
 6    Path,
 7    Response,
 8    get,
 9    retry,
10)
11
12
13class GitHubService(AsyncSession):
14    async def after_request(self, response: Response) -> Response:
15        response.raise_for_status()
16        return response
17
18    @retry(
19        max_retries=3,
20        backoff_factor=0.5,
21        retry_on=(HTTPServerError, TimeoutError),
22        retry_on_status=(502, 503, 504),
23        max_delay=4.0,
24    )
25    @get("/users/{user}/repos")
26    async def list_repositories(
27        self, response: Response, user: Annotated[str, Path]
28    ) -> list[dict[str, Any]]:
29        return response.json()

예외 기반 재시도에는 retry_on 을 사용합니다. 세션 수준 after_request() 훅에서 Response.raise_for_status() 를 호출하면 4xx 또는 5xx 응답이 해당 HTTPException 하위 클래스로 변환되고(예외 (Exception) 참고), retry_on 이 이 예외를 잡을 수 있습니다. 또는 요청에 raise_on=True 를 지정하면 요청 결과를 반환하기 전에 200 이외의 모든 상태를 실패로 처리합니다.

상태 코드 기반 재시도에는 retry_on_status 를 사용하며 예외나 after_request() 훅이 필요하지 않습니다. 최종 응답은 정상적으로 반환하면서, 응답 상태 자체를 재시도해야 할 때 사용합니다:

@retry(max_retries=3, retry_on_status=(429, 502, 503, 504))
@get("/users/{user}/repos")
async def list_repositories(self, response: Response, user: Annotated[str, Path]):
    return response.json()

백오프와 재시도 범위

기본값은 최초 요청 이후 최대 세 번 재시도하며, HTTPServerError 가 이를 유발합니다. 반환된 5xx 응답에서 이 예외를 발생시키려면 Response.raise_for_status() 또는 raise_on=True 를 사용합니다. retry_on_status 의 기본값은 빈 튜플입니다.

retry_on 은 예외 클래스 하나 또는 튜플을 받으므로 TimeoutError 같은 전송 단계 실패를 HTTPServerError 와 함께, 또는 대신 사용할 수 있습니다. retry_on_status 도 하나의 HTTP 상태 코드 또는 100부터 599까지의 상태 코드 튜플을 받습니다. 재시도할 시도의 응답은 자동으로 닫습니다. 재시도 횟수를 모두 소진하면 마지막으로 일치한 상태 응답은 미리 닫지 않고 일반 응답 처리 과정을 계속 진행합니다.`n` 번째 재시도까지의 대기 시간은 backoff_factor * 2 ** (n - 1) 초이고, max_delay 를 정해두면 그 값이 상한이 됩니다. 위 예제 기본값(backoff_factor=0.5, max_delay=4.0)이라면 대기 시간은 순서대로 0.5, 1.0, 2.0, 4.0 (상한 적용) 초가 됩니다.

retry_on accepts one exception class or a tuple, so transport-level failures such as TimeoutError can be added alongside HTTPServerError, or used in its place. retry_on_status likewise accepts one HTTP status code or a tuple of status codes from 100 through 599. Responses from attempts that will be retried are closed automatically. When the retry budget is exhausted, the final matching-status response is not pre-closed and proceeds through normal response handling.

경고

예외 재시도는 요청 전송, 세션 수준 after_request() 훅, raise_on=True 검증에서 발생한 실패를 처리합니다. 상태 재시도는 요청 수준 after_hook 콜백이 실행되기 전에 응답을 검사합니다. 요청 수준 after_hook (Hooking 기능 참고)은 재시도 작업이 끝난 뒤 실행되므로, 여기서 발생한 예외는 재시도되지 않습니다.

참고

max_retries, backoff_factor, max_delay 는 전부 유한하고 음수가 아닌 값이어야 합니다. 잘못된 값을 넣으면 @retry 가 적용되는 순간 TypeError 나 ValueError 가 납니다.

경고

Automatic retries are limited to idempotent HTTP methods. Retrying a POST, PATCH, or another non-idempotent request can duplicate a server-side operation, so it must be explicitly enabled with retry_unsafe=True.

데코레이션 순서

@retry 는 같은 메소드에서 @request (또는 @get, @post 등) 위에 두든 아래에 두든 상관없습니다. 둘 다 똑같은 재시도 설정이 적용됩니다:

# @retry above @request: applied directly to the built RequestCore.
@retry(max_retries=5, backoff_factor=0.2)
@get("/users/{user}/repos")
async def list_repositories(self, response: Response, user: Annotated[str, Path]):
    return response.json()

# @retry below @request: stashed until @request builds the RequestCore.
@get("/users/{user}/repos")
@retry(max_retries=5, backoff_factor=0.2)
async def list_repositories(self, response: Response, user: Annotated[str, Path]):
    return response.json()

Reference

class RetryConfig

재시도 횟수, 예외/상태 매칭, 지수 백오프를 설정합니다.

매개변수:
  • max_retries (int) – 최초 요청 이후의 최대 시도 횟수입니다.

  • backoff_factor (float) – 각 재시도 전 지수적으로 증가하는 지연 시간을 계산하는 데 사용되는 배율입니다.

  • retry_on (tuple[type[Exception], ...]) – 재시도를 유발하는 예외 클래스입니다.

  • max_delay (Optional[float]) – 최대 지연 시간(초)이며, 상한이 없으면 None 입니다.

  • retry_unsafe (bool) – Whether retries are explicitly allowed for non-idempotent HTTP methods such as POST and PATCH.

  • retry_on_status (tuple[int, ...]) – 예외를 발생시키지 않고도 재시도를 유발하는 100부터 599까지의 HTTP 응답 상태입니다.

예외 발생:
  • TypeError – 재시도 횟수, 지연 시간 또는 재시도 필터의 타입이 올바르지 않은 경우 발생합니다.

  • ValueError – 재시도 횟수나 지연 시간이 음수이거나 유한하지 않은 경우 발생합니다.

참고

max_retries 는 최초 요청을 포함하지 않습니다. n 번째 재시도 전 지연 시간은 backoff_factor * 2 ** (n - 1) 이며, 상한이 설정되어 있으면 max_delay 로 제한됩니다.

async execute_async(make_request_func: Callable[[...], Awaitable[tuple[Response, Any]]]) → tuple[Response, Any]

비동기 요청을 실행하고, 일치하는 실패에 대해 재시도합니다.

매개변수:

make_request_func (Callable[..., Awaitable[tuple[Response, Any]]]) – 원본 응답과 응답 파이프라인 결과를 반환하는, 인자를 받지 않는 호출 가능 객체입니다.

반환:

최종 시도의 원본 응답과 처리된 결과입니다. 재시도 횟수를 소진하면 일치한 상태의 응답을 반환합니다.

반환 형식:

tuple[Response, Any]

예외 발생:

Exception – 일치하지 않는 예외는 즉시 다시 발생시키며, 재시도 횟수를 모두 소진하면 마지막으로 일치했던 예외를 다시 발생시킵니다.

execute_sync(make_request_func: Callable[[...], tuple[Response, Any]]) → tuple[Response, Any]

동기 요청을 실행하고, 일치하는 실패에 대해 재시도합니다.

매개변수:

make_request_func (Callable[..., tuple[Response, Any]]) – 원본 응답과 응답 파이프라인 결과를 반환하는, 인자를 받지 않는 호출 가능 객체입니다.

반환:

최종 시도의 원본 응답과 처리된 결과입니다. 재시도 횟수를 소진하면 일치한 상태의 응답을 반환합니다.

반환 형식:

tuple[Response, Any]

예외 발생:

Exception – 일치하지 않는 예외는 즉시 다시 발생시키며, 재시도 횟수를 모두 소진하면 마지막으로 일치했던 예외를 다시 발생시킵니다.

@retry(max_retries: int = 3, *, backoff_factor: float = 1.0, retry_on: tuple[type[Exception], ...] | type[Exception] = (<class 'ahttp_client.exception.HTTPServerError'>,), retry_on_status: tuple[int, ...] | int = (), max_delay: float | None = None, retry_unsafe: bool = False) → RequestDecorator[Any, Any]

지수 백오프를 이용해 실패 시 재시도하도록 요청을 데코레이팅합니다.

매개변수:
  • max_retries (int) – 최초 요청 이후의 최대 재시도 횟수입니다.

  • backoff_factor (float) – 지수 백오프 지연 시간에 적용되는 배율입니다. delay = backoff_factor * 2 ** (attempt - 1)

  • retry_on (tuple[type[Exception], ...] | type[Exception]) – 재시도를 유발하는 예외 타입입니다. 기본값은 HTTPServerError (5xx 응답)입니다.

  • retry_on_status (tuple[int, ...] | int) – 예외 없이 재시도를 유발하는 HTTP 응답 상태입니다. 기본값은 빈 튜플입니다.

  • max_delay (Optional[float]) – 대기 시간의 상한(초)입니다. None 이면 상한이 없습니다.

  • retry_unsafe (bool) – Explicitly allow retries for non-idempotent methods. Defaults to False so POST, PATCH, and other unsafe requests are not repeated accidentally.

반환:

재시도 설정을 요청에 붙이는 데코레이터입니다.

반환 형식:

RequestDecorator[Any, Any]

예외 발생:
  • TypeError – 재시도 횟수, 지연 시간 또는 재시도 필터의 타입이 올바르지 않은 경우 발생합니다.

  • ValueError – 재시도 횟수나 지연 시간이 음수이거나 유한하지 않은 경우 발생합니다.

참고

요청 전송 또는 세션 수준 after_request 훅에서 발생한 예외는 재시도 대상입니다. retry_on_status 는 예외 없이 반환된 원본 응답 상태를 검사합니다. 요청 수준 after_hook 콜백은 재시도 작업이 끝난 뒤 실행되므로 그 범위 밖입니다.