从requests请求重试到万能重试装饰器
重试,在编写代码的过程中,是一个很常见的需求。
比如:
- 请求重试(例如:超时)
- 文件占用
- IO阻塞等待
那么,我们如何编写重试的代码呢?
本文将从请求重试开始,带大家从简单的超时重试,最后编写到万能错误重试。
主要涉及内容:
- requests adapter
- 函数装饰器
- 类装饰器
话不多说,start!
因为我们需要从 requests
请求重试开始,为了方便测试请求,我们用 flask
编写一个简单的服务器,用于请求测试。
准备请求服务器
服务器的功能比较简单,用来查看请求次数和观察是否重试成功,flask_server.py
代码如下:
from time import sleep
from flask import Flask, jsonify, Response
app: Flask = Flask(__name__)
retry_count: int = 0 # 用于重试请求的计数
@app.route("/api/retry", methods=["GET"])
def retry_api() -> Response:
"""
延时 1s 的请求接口, 响应时间 > 1s。
:return:
"""
global retry_count
retry_count += 1
print(f"这是第{retry_count}次请求")
if retry_count < 3:
sleep(1)
else:
retry_count = 0 # 计数清零
return jsonify({
"msg": "已经三次了哦!"})
if __name__ == '__main__':
app.run()
代码比较简单,由于没有找到好用的flask
上下文来完成计数需求,这里为了简单操作,就直接应用了全局变量来计数(仅用于测试,未加锁),而没有使用redis
数据库来计数了。
编写好之后,我们运行代码即可。这样,我们用来测试重试的服务器就准备好了。
接下来,我们先来看看一般的 requests
超时请求如何实现。
1.requests
请求重试(常见版本)
我们用 try...except...
语句捕捉timeout
错误。进行循环重试即可。我们编写一个函数 get_data
,normal.py
代码如下:
from typing import Dict, Any
import requests
BaseDictData = Dict[str, Any]
def get_data(url: str, max_retry: int = 0, time_out: float = 3., **kwargs) -> BaseDictData:
"""自动重试 timeout 错误 的方法"""
params: BaseDictData = kwargs.get("params", {
}) # 不管你传了什么奇怪的东西, 我只收这个
headers: BaseDictData = kwargs.get("headers", {
}) # 同上
for i in range(max_retry + 1):
"""进行最大重试次数的遍历"""
try:
response: requests.Response = requests.get(
url=url,
params=params,
headers=headers,
timeout=time_out,
)
except requests.ReadTimeout:
print(f"第{i + 1}次请求失败,正在重试。")
else:
return response.json() # 没有错误,直接返回
print(f"{max_retry + 1} 次请求都失败了,返回空值,便于后续逻辑处理。。。")
return {
}
if __name__ == '__main__':
print(get_data("http://localhost:5000/api/retry", max_retry=1, time_out=.01))
在该函数中,我们利用 requests
库本身的 timeout
参数进行错误捕捉。整体比较简单,设计逻辑即: