其他
Python 外部服务调用出现瞬时故障时:用重试、指数退避…
适用于为 Python 外部服务调用、网络操作、微服务添加重试、超时、退避和容错处理的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 56/100 ×0.15
适用场景
Python 外部服务调用出现瞬时故障时通用
解决思路
- 区分瞬态和永久失败:只重试瞬态错误(网络超时、临时服务问题),不重试永久错误(无效凭证、错误请求)。
- 使用指数退避:在重试之间增加等待时间,避免压垮正在恢复的服务。
- 添加抖动:给退避加入随机性,防止大量客户端同时重试造成 thundering herd。
- 有界重试:同时限制尝试次数和总持续时间,防止无限重试循环。
- 快速开始:使用 tenacity 的 @retry 装饰器,设置 stop=stop_after_attempt(3),wait=wait_exponential_jitter(initial=1, max=10),包装 call_external_service,例如 httpx.post('https://api.example.com', json=request).json()。
- Pattern 1:使用 tenacity 库实现生产级重试逻辑;简单场景考虑内置重试功能或轻量自定义实现。
- Pattern 1 具体:定义 TRANSIENT_ERRORS = (ConnectionError, TimeoutError, OSError),使用 retry=retry_if_exception_type(TRANSIENT_ERRORS)、stop=stop_after_attempt(5) | stop_after_delay(60)、wait=wait_exponential_jitter(initial=1, max=30),在 fetch_data(url) 中执行 httpx.get(url, timeout=30)、response.raise_for_status()、返回 response.json()。
- Pattern 2:仅重试合适错误,白名单特定瞬态异常;不要重试 ValueError、TypeError、AuthenticationError、HTTP 4xx(除 429)。
- Pattern 2 具体:定义 RETRYABLE_EXCEPTIONS = (ConnectionError, TimeoutError, httpx.ConnectTimeout, httpx.ReadTimeout),使用 @retry(retry=retry_if_exception_type(RETRYABLE_EXCEPTIONS), stop=stop_after_attempt(3), wait=wait_exponential_jitter(initial=1, max=10)),在 resilient_api_call(endpoint) 中执行 httpx.get(endpoint, timeout=10).json()。
- Pattern 3:对表示瞬态问题的 HTTP 状态码进行重试。
- Pattern 3 具体:定义 RETRY_STATUS_CODES = {429, 502, 503, 504},编写 should_retry_response(response) 返回 response.status_code in RETRY_STATUS_CODES,使用 retry=retry_if_result(should_retry_response)、stop=stop_after_attempt(3)、wait=wait_exponential_jitter(initial=1, max=10),在 http_request(method, url, **kwargs) 中执行 httpx.request(method, url, timeout=30, **kwargs)。
- Pattern 4:同时处理网络异常和 HTTP 状态码重试。
- Pattern 4 具体:定义 TRANSIENT_EXCEPTIONS = (ConnectionError, TimeoutError, httpx.ConnectError, httpx.ReadTimeout),RETRY_STATUS_CODES = {429, 500, 502, 503, 504},用 is_retryable_response 检查状态码;使用 retry=(retry_if_exception_type(TRANSIENT_EXCEPTIONS) | retry_if_result(is_retryable_response))、stop=stop_after_attempt(5)、wait=wait_exponential_jitter(initial=1, max=30)、before_sleep=before_sleep_log(logger, logging.WARNING),在 robust_http_call 中执行 httpx.request(method, url, timeout=30, **kwargs)。
- 需要更多细节时,读取 references/details.md 中的 Advanced Patterns 部分。
- 只重试瞬态错误:不要重试 bug 或认证失败。
- 使用指数退避:给服务时间恢复。
- 添加抖动:防止同步重试造成 thundering herd。
- 限制总持续时间:stop_after_attempt(5) | stop_after_delay(60)。
- 记录每次重试:静默重试会隐藏系统性问题。
- 使用装饰器:将重试逻辑与业务逻辑分离。
- 注入依赖:让基础设施可测试。
- 处处设置超时:每个网络调用都需要超时。
- 优雅失败:对非关键路径返回缓存/默认值。
- 监控重试率:高重试率表示底层问题。
适用边界 · 注意事项
- 不要用于重试永久性错误,如 ValueError、TypeError、AuthenticationError、HTTP 4xx(除 429)。
- 不要在没有尝试次数上限、总时长上限或超时设置的情况下套用重试逻辑。
- 不要静默重试而不记录日志或监控重试率。