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

解释

  1. 装饰器定义retryonexception 是一个装饰器工厂函数,它接受三个参数(retriesdelay 和 backoff),并返回一个装饰器函数 decorator。这个装饰器函数再接受一个函数 func 并返回一个新的函数 wrapper

  2. 重试逻辑:在 wrapper 函数内部,使用 while 循环来尝试执行被装饰的函数 func。如果函数执行成功(没有抛出异常),则返回结果。如果函数抛出异常,则增加尝试次数 attempt,计算等待时间 wait_time(使用指数退避策略),打印错误信息,然后等待指定的时间后再次尝试。

  3. 异常处理:如果达到最大重试次数 retries 后仍然失败,则重新抛出异常,以便调用者可以捕获并处理它。

  4. 装饰器应用:使用 @retryonexception(retries=5, delay=1, backoff=1.5) 来装饰 fetch_data_from_api 函数,指定最大重试次数为5次,初始等待时间为1秒,等待时间增长因子为1.5。

注意事项

  • 重试装饰器对于可能因临时问题而失败的操作非常有用,但不应滥用。对于持续失败的操作,应该考虑使用其他错误处理策略(如回退、告警、记录错误日志等)。
  • 在实际应用中,你可能希望将重试策略(如重试次数、等待时间等)放在一个单独的配置文件中,而不是直接在代码中硬编码。
  • 当使用重试装饰器时,请确保被装饰的函数是幂等的(即多次调用不会改变系统的状态或产生不同的结果)。
posted @ 2024-12-20 14:54  公子Learningcarer  阅读(18)  评论(0编辑  收藏  举报