你有没有遇到过这种情况:写好的脚本跑着跑着,突然因为网络抖动断了连接,整个任务就卡死了?重新跑一遍费时费力,尤其是处理大批量数据或者调用外部 API 的时候,特别让人抓狂。
为什么需要自动重试
网络不是永远稳定的。服务器可能瞬时过载,DNS 解析可能延迟,Wi-Fi 信号可能波动。这些都可能导致一次请求超时。但大多数情况下,几秒后再试一次,事情就过去了。与其手动重启程序,不如让代码自己“再努努力”。
简单的重试逻辑长什么样
以 Python 为例,最基础的重试可以用一个 while 循环加 try-except 实现:
import requests
import time
max_retries = 3
retry_count = 0
while retry_count < max_retries:
try:
response = requests.get('https://api.example.com/data', timeout=5)
print(response.json())
break # 成功就跳出循环
except requests.exceptions.Timeout:
retry_count += 1
print(f'请求超时,第 {retry_count} 次重试...')
time.sleep(2) # 等两秒再试
except requests.exceptions.RequestException as e:
print(f'请求出错:{e}')
break
别傻等,指数退避更聪明
如果每次失败都隔 2 秒重试,前几次可能还好,但如果连续失败,说明问题没那么快恢复。这时候可以采用“指数退避”策略:第一次等 1 秒,第二次等 2 秒,第三次等 4 秒……避免在短时间内疯狂请求给服务器添堵。
稍微改一下上面的逻辑:
import time
import random
def make_request_with_backoff():
max_retries = 5
for i in range(max_retries):
try:
return requests.get('https://api.example.com/data', timeout=5)
except requests.exceptions.Timeout:
if i == max_retries - 1:
raise # 最后一次也失败,抛出异常
wait_time = (2 ** i) + random.uniform(0, 1) # 加点随机性
time.sleep(wait_time)
用现成轮子更省心
自己写重试逻辑容易漏掉边界情况。Python 里有个很实用的库叫 tenacity,专门干这个事。
先安装:
pip install tenacity
然后这样用:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(5), wait=wait_exponential(multiplier=1, max=10))
def fetch_data():
response = requests.get('https://api.example.com/data', timeout=5)
return response.json()
# 调用它,失败会自动重试
print(fetch_data())
上面这段代码的意思是:最多尝试 5 次,等待时间按指数增长(1s, 2s, 4s...),最长不超过 10 秒。简洁又可靠。
重试不是万能的
有些错误重试也没用,比如认证失败、接口不存在。盲目重试反而浪费资源。建议只对网络超时、连接中断这类临时性错误(transient errors)启用重试。
还可以结合日志记录,每次重试都留下痕迹,方便排查问题。线上服务中,搭配监控和告警,能让系统更健壮。
说到底,网络连接超时自动重试不是炫技,而是让程序更有容错能力。就像坐地铁,偶尔错过一站没关系,下一站还能赶上——代码也该有这样的弹性。