|
30 | 30 | import msgspec |
31 | 31 | import structlog |
32 | 32 | from pydantic import BaseModel |
33 | | -from retryhttp import retry, wait_retry_after |
34 | | -from tenacity import before_log, wait_random_exponential |
| 33 | +from tenacity import ( |
| 34 | + before_log, |
| 35 | + retry, |
| 36 | + retry_if_exception, |
| 37 | + stop_after_attempt, |
| 38 | + wait_random_exponential, |
| 39 | +) |
35 | 40 | from uuid6 import uuid7 |
36 | 41 |
|
37 | 42 | from airflow.configuration import conf |
@@ -832,6 +837,14 @@ def noop_handler(request: httpx.Request) -> httpx.Response: |
832 | 837 | API_TIMEOUT = conf.getfloat("workers", "execution_api_timeout") |
833 | 838 |
|
834 | 839 |
|
| 840 | +def _should_retry_api_request(exception: BaseException) -> bool: |
| 841 | + """Determine if an API request should be retried based on the exception type.""" |
| 842 | + if isinstance(exception, httpx.HTTPStatusError): |
| 843 | + return exception.response.status_code >= 500 |
| 844 | + |
| 845 | + return isinstance(exception, httpx.RequestError) |
| 846 | + |
| 847 | + |
835 | 848 | class Client(httpx.Client): |
836 | 849 | def __init__(self, *, base_url: str | None, dry_run: bool = False, token: str, **kwargs: Any): |
837 | 850 | if (not base_url) ^ dry_run: |
@@ -864,21 +877,17 @@ def __init__(self, *, base_url: str | None, dry_run: bool = False, token: str, * |
864 | 877 | **kwargs, |
865 | 878 | ) |
866 | 879 |
|
867 | | - _default_wait = wait_random_exponential(min=API_RETRY_WAIT_MIN, max=API_RETRY_WAIT_MAX) |
868 | | - |
869 | 880 | def _update_auth(self, response: httpx.Response): |
870 | 881 | if new_token := response.headers.get("Refreshed-API-Token"): |
871 | 882 | log.debug("Execution API issued us a refreshed Task token") |
872 | 883 | self.auth = BearerAuth(new_token) |
873 | 884 |
|
874 | 885 | @retry( |
875 | | - reraise=True, |
876 | | - max_attempt_number=API_RETRIES, |
877 | | - wait_server_errors=_default_wait, |
878 | | - wait_network_errors=_default_wait, |
879 | | - wait_timeouts=_default_wait, |
880 | | - wait_rate_limited=wait_retry_after(fallback=_default_wait), # No infinite timeout on HTTP 429 |
| 886 | + retry=retry_if_exception(_should_retry_api_request), |
| 887 | + stop=stop_after_attempt(API_RETRIES), |
| 888 | + wait=wait_random_exponential(min=API_RETRY_WAIT_MIN, max=API_RETRY_WAIT_MAX), |
881 | 889 | before_sleep=before_log(log, logging.WARNING), |
| 890 | + reraise=True, |
882 | 891 | ) |
883 | 892 | def request(self, *args, **kwargs): |
884 | 893 | """Implement a convenience for httpx.Client.request with a retry layer.""" |
|
0 commit comments