让 Python API 重试更可靠:幂等、退避与时间预算
API 调用偶尔超时或返回 5xx 很正常,但“失败就重试”可能把短暂故障放大成流量风暴,也可能让订单重复创建。设计重试时,先判断错误是否暂时、请求能否安全重复,以及重试最多占用多久。
先看幂等性。GET、HEAD 通常可重复读取;创建订单、扣款等 POST 可能已经在服务端成功,只是响应丢了。只有当服务端支持幂等键时,才应在多次尝试中复用同一个 Idempotency-Key。否则写操作遇到读超时,应先查询结果或走业务补偿,不能把“没收到响应”当成“没有执行”。
再筛选错误。连接超时、连接重置,以及 408、429、500、502、503、504 往往可以重试;参数错误、鉴权失败等明确的 4xx 通常应直接返回。遇到 429 或 503 时,还要尊重服务端给出的 Retry-After。
下面是一个简化示例:只重试可重复的读取请求,或明确带有幂等键的调用;超时分别限制连接和读取时间,并使用带随机抖动的指数退避。
import random, time, requests
RETRYABLE = {408, 429, 500, 502, 503, 504}
def request(session, method, url, *, key=None, attempts=4):
method = method.upper()
safe = method in {"GET", "HEAD", "OPTIONS"} or bool(key)
headers = {"Idempotency-Key": key} if key else {}
for attempt in range(attempts):
try:
response = session.request(method, url, headers=headers, timeout=(3, 10))
except (requests.Timeout, requests.ConnectionError):
if not safe or attempt == attempts - 1:
raise
else:
if response.status_code not in RETRYABLE or not safe or attempt == attempts - 1:
return response
time.sleep(random.uniform(0, min(8, 0.5 * 2 ** attempt)))
上线前还要给整个业务流程设置 deadline,避免每次超时和等待累加到不可接受的时长。重试放在一个清晰的调用层,记录错误类型、尝试次数和总等待时间,方便观察真实效果。重试只能缓冲短暂波动;依赖长期不可用时,应快速失败、限流或熔断,给系统留出恢复空间。
- 点赞
- 收藏
- 关注作者
评论(0)