python 重试装饰器@retryonexception 用法及案例
在Python中,重试装饰器(@retryonexception
)是一种用于在函数或方法执行过程中遇到异常时自动重试的装饰器。这种装饰器对于处理可能由于临时问题(如网络延迟、资源争用等)而失败的操作非常有用。下面是一个简单的重试装饰器的实现及其用法案例:
重试装饰器实现
import time
import functools
def retryonexception(retries=3, delay=2, backoff=2):
"""
重试装饰器,在遇到异常时重试指定的次数。
参数:
retries (int): 最大重试次数。
delay (int/float): 初始等待时间(秒)。
backoff (int/float): 等待时间增长因子(每次重试时等待时间乘以这个因子)。
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempt = 0
while attempt < retries:
try:
return func(*args, **kwargs)
except Exception as e:
attempt += 1
wait_time = delay * (backoff ** (attempt - 1))
print(f"Attempt {attempt} failed: {e}. Retrying after {wait_time:.2f} seconds...")
time.sleep(wait_time)
if attempt == retries:
print(f"After {attempt} attempts, function '{func.__name__}' failed.")
raise # 重新抛出异常,以便调用者可以处理它
return wrapper
return decorator
用法案例
@retryonexception(retries=5, delay=1, backoff=1.5)
def fetch_data_from_api(url):
# 模拟从API获取数据,这里可能会抛出异常
import requests
response = requests.get(url)
response.raise_for_status() # 如果响应状态码不是200,会抛出HTTPError异常
return response.json()
# 调用函数,这里我们假设URL是有效的,但为了演示,我们可以手动触发异常
try:
data = fetch_data_from_api("http://example.com/api/data")
print(data)
except Exception as e:
print(f"Failed to fetch data: {e}")
输出结果(假设API调用失败并触发重试)
Attempt 1 failed: HTTPError 404 Client Error: Not Found for url: http://example.com/api/data. Retrying after 1.00 seconds...
Attempt 2 failed: HTTPError 404 Client Error: Not Found for url: http://example.com/api/data. Retrying after 1.50 seconds...
Attempt 3 failed: HTTPError 404 Client Error: Not Found for url: http://example.com/api/data. Retrying after 2.25 seconds...
Attempt 4 failed: HTTPError 404 Client Error: Not Found for url: http://example.com/api/data. Retrying after 3.38 seconds...
After 5 attempts, function 'fetch_data_from_api' failed.
Failed to fetch data: HTTPError 404 Client Error: Not Found for url: http://example.com/api/data
解释
-
装饰器定义:
retryonexception
是一个装饰器工厂函数,它接受三个参数(retries
、delay
和backoff
),并返回一个装饰器函数decorator
。这个装饰器函数再接受一个函数func
并返回一个新的函数wrapper
。 -
重试逻辑:在
wrapper
函数内部,使用while
循环来尝试执行被装饰的函数func
。如果函数执行成功(没有抛出异常),则返回结果。如果函数抛出异常,则增加尝试次数attempt
,计算等待时间wait_time
(使用指数退避策略),打印错误信息,然后等待指定的时间后再次尝试。 -
异常处理:如果达到最大重试次数
retries
后仍然失败,则重新抛出异常,以便调用者可以捕获并处理它。 -
装饰器应用:使用
@retryonexception(retries=5, delay=1, backoff=1.5)
来装饰fetch_data_from_api
函数,指定最大重试次数为5次,初始等待时间为1秒,等待时间增长因子为1.5。
注意事项
- 重试装饰器对于可能因临时问题而失败的操作非常有用,但不应滥用。对于持续失败的操作,应该考虑使用其他错误处理策略(如回退、告警、记录错误日志等)。
- 在实际应用中,你可能希望将重试策略(如重试次数、等待时间等)放在一个单独的配置文件中,而不是直接在代码中硬编码。
- 当使用重试装饰器时,请确保被装饰的函数是幂等的(即多次调用不会改变系统的状态或产生不同的结果)。