別讓一次超時拖垮整個任務:給 Python requests 加上重試與超時

举报
yd_298795255 发表于 2026/11/11 09:55:54 2026/11/11
【摘要】 调用外部接口时,最怕的不是返回错误,而是请求一直没有返回。一个没有设置超时的 requests.get(),在网络抖动、对方服务假死时可以挂住几分钟甚至更久;如果它跑在定时任务或接口里,整个任务都会被拖住,线程池被占满,最后连正常的请求也进不来。所以第一条规则很简单:任何一次网络调用都要有超时,而且重试要有分寸。 一、先把超时写死,不要用默认值requests 的 timeout 默认是无限...

调用外部接口时,最怕的不是返回错误,而是请求一直没有返回。一个没有设置超时的 requests.get(),在网络抖动、对方服务假死时可以挂住几分钟甚至更久;如果它跑在定时任务或接口里,整个任务都会被拖住,线程池被占满,最后连正常的请求也进不来。所以第一条规则很简单:任何一次网络调用都要有超时,而且重试要有分寸。

一、先把超时写死,不要用默认值

requests 的 timeout 默认是无限等待,一定要显式传入。建议用元组分开连接超时和读取超时,例如 timeout=(3, 10):连接 3 秒建连不上就放弃,读取 10 秒没有数据也放弃。连接超时可以短一点,读取超时按接口正常耗时放宽两到三倍。把超时写成常量放在配置里,而不是散落在每个调用处;超时异常要单独捕获 Timeout,而不是笼统地捕获 Exception 后当成业务失败重试。

二、用 urllib3 的 Retry 做有节制的重试

不要自己写 while True 加 sleep。requests 底层是 urllib3,可以挂一个 HTTPAdapter,配合 Retry 实现指数退避:

from requests import Session
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=(429, 500, 502, 503, 504),
    allowed_methods=("GET", "HEAD", "OPTIONS"),
    raise_on_status=False,
)
adapter = HTTPAdapter(max_retries=retry)
session = Session()
session.mount("https://", adapter)
session.mount("http://", adapter)
resp = session.get("https://example.com/api", timeout=(3, 10))
resp.raise_for_status()

backoff_factor=1 时,等待时间大约是 0 秒、2 秒、4 秒递增,给服务端留出恢复时间;不要把 total 设得太大,重试 3 次已经足够覆盖大多数瞬时故障。

三、只对幂等请求重试,写操作要格外小心

GET、HEAD 这类读操作重试一般是安全的,但 POST、PUT、DELETE 不一定。重复提交订单、扣款、发短信,后果比一次失败严重得多。所以默认只重试安全方法;写操作确实需要重试时,一定要带幂等键,例如在请求头里传一个本次唯一的 Idempotency-Key,让服务端去重,或者先查一次状态再决定是否补发。客户端错误 400、401、403、404 通常不是网络问题,重试也不会变好,应当直接返回错误,不要浪费次数。

四、给重试加总上限和日志

单次超时 10 秒、重试 3 次,最坏情况也要 40 秒以上,调用方必须能接受这个上限。可以在外层再设一个总的截止时间,或者把重试次数和超时写进监控:记录每次重试的状态码、耗时和最终结果,方便事后判断是偶发抖动还是服务端持续故障。如果短时间内大量重试集中在同一接口,要考虑熔断或降级,先返回缓存和默认值,而不是继续压垮对方。

五、一个可以直接用的小模板

把上面的做法封装成一个函数:创建带重试的 Session、统一的超时、统一的异常处理和日志,业务代码只关心成功和失败两种结果。这样的模板在爬虫、定时同步、支付回调查询这类场景里几乎可以直接复用。记住最终目标不是「永远不失败」,而是失败得快、失败得清楚、恢复得体面:超时让调用方及时止损,重试让瞬时故障自动恢复,幂等和上限则保证重试本身不会制造新的事故。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。