retry、retrying和tenacity是Python中常用的三个模块,用于处理函数调用时的重试机制。它们的主要区别如下:
- retry模块:
- 是一个简单的模块,提供了一个简单的重试机制。它通过在调用失败时自动重试一定次数来帮助您处理错误。
- 可以通过设置参数来控制重试次数、重试间隔等。
- 可以通过Retry类来定义自己的重试策略。
- retrying模块:
- 是一个基于contextlib的模块,提供了一个更高级的重试机制。它通过使用上下文管理器来处理函数调用,并在调用失败时自动重试。
- 可以通过设置参数来控制重试次数、重试间隔等。
- 可以通过Retry类来定义自己的重试策略。
- 可以使用@retrying装饰器来包装需要重试的函数。
- tenacity模块:
- 是一个功能强大的模块,提供了一个更灵活的重试机制。它通过使用装饰器来处理函数调用,并在调用失败时自动重试。
- 可以通过设置参数来控制重试次数、重试间隔等。
- 可以通过Retrying类来定义自己的重试策略。
- 可以使用@tenacity.retrying装饰器来包装需要重试的函数。
总的来说,这三个模块都可以用于处理函数调用时的重试机制,但它们的使用方式和功能略有不同。根据您的需求和偏好,可以选择适合您的模块来使用。
程序运行过程中,经常遇到失败的情况,这个时候我们一般会通过try块去进行重试,但是每次都写那么一堆try块,太麻烦。于是就有了retrying
模块
安装
retrying模块的安装很简单直接用匹配安装即可。
pip install retrying
用法
retrying 模块是一个用于在Python中进行延迟重试的装饰器,它可以处理大多数常见的异常。下面是retrying模块的常见用法:
使用装饰器
使用@retrying装饰器可以重试某个函数,最多尝试次数由stop_after_attempt参数指定。如果成功执行函数,则停止重试。如果遇到异常,则重新尝试。
def __init__(self,
stop: Any = None,
wait: Any = None,
stop_max_attempt_number: Any = None,
stop_max_delay: Any = None,
wait_fixed: Any = None,
wait_random_min: Any = None,
wait_random_max: Any = None,
wait_incrementing_start: Any = None,
wait_incrementing_increment: Any = None,
wait_incrementing_max: Any = None,
wait_exponential_multiplier: Any = None,
wait_exponential_max: Any = None,
retry_on_exception: Any = None,
retry_on_result: Any = None,
wrap_exception: bool = False,
stop_func: Any = None,
wait_func: Any = None,
wait_jitter_max: Any = None,
before_attempts: Any = None,
after_attempts: Any = None) -> None
默认行为是永久重试而不等待。
-
stop_max_attempt_number
:在停止之前尝试的最大次数,最后一次如果还是有异常则会抛出异常,停止运行,默认为5次 -
stop_max_delay
:最大延迟时间,大概意思就是:如果调用的函数出现异常,那么就会重复调用这个函数,最大调用时间,默认为100毫秒 -
wait_fixed
:两次调用方法期间停留时长, 如果出现异常则会一直重复调用,默认 1000毫秒 -
wait_random_min
:在两次调用方法停留时长,停留最短时间,默认为0 -
wait_random_max
:在两次调用方法停留时长,停留最长时间,默认为1000毫秒 -
wait_incrementing_start
和wait_incrementing_increment
:每调用一次则会增加的时长,默认 100毫秒 -
wait_exponential_multiplier
和wait_exponential_max
:以指数的形式产生两次retrying之间的停留时间,产生的值为2^previous_attempt_number * wait_exponential_multiplier
,previous_attempt_number
是前面已经retry的次数,如果产生的这个值超过了wait_exponential_max
的大小,那么之后两个retrying之间的停留值都为wait_exponential_max
。 -
retry_on_exception
: 指定一个函数,如果此函数返回指定异常,则会重试,如果不是指定的异常则会退出retry_on_exception
参数的大体思想是:接收一个自定义函数is_MyError
,在is_MyError
函数里判断了是不是属于ValueError
,IOError
,ConnectionError
三种异常;random_with_retry()
函数如果抛出了异常,会去函数is_MyError()
判断返回的是True还是False,如果是True则继续重试,如果是False则立即停止并抛出异常。 -
retry_on_result
:指定一个函数,如果指定的函数返回True,则重试,否则抛出异常退出判断业务函数返回哪些结果时需要重试,思想和
retry_on_exception
参数类似。 -
wrap_exception
:参数设置为True/False,如果指定的异常类型,包裹在RetryError中,会看到RetryError
和程序抛的Exception error
-
stop_func
: 每次抛出异常时都会执行的函数,如果和stop_max_delay、stop_max_attempt_number配合使用,则后两者会失效指定的。 stop_func会有两个参数:attempts, delay -
wait_func
:和stop_func用法差不多,不多描述
例如:
from retrying import retrying
@retrying(stop_after_attempt=3, wait_random_min=1, wait_random_max=2)
def my_function():
# your function here
pass
在这个例子中,如果my_function在3次尝试中仍然抛出异常,它将尝试最多4次,每次等待1到2秒之间随机的时间。如果my_function在3次尝试中仍然抛出异常,它将会在后续尝试中被重新调用。
自定义重试策略
除了使用默认的策略外,还可以自定义重试策略。自定义策略需要实现RetryStrategy接口,并实现should_retry()方法。在实现自定义策略时,可以设置最大尝试次数、等待时间等参数。
例如:
from retrying import RetryStrategy, RetryOnException, RetryOnTimeout, RetryOnMaxRetriesExceeded
from time import sleep
class CustomStrategy(RetryStrategy):
def should_retry(self, attempt_number, exception):
return attempt_number < 5 and isinstance(exception, (Exception,)) and not self.is_timeout(exception)
def is_timeout(self, exception):
return False # 设置自定义的超时策略,此处不进行超时判断
my_strategy = CustomStrategy()
my_function = retrying(stop_after_attempt=5, strategy=my_strategy)
在这个例子中,自定义了重试策略,其中should_retry()方法返回True表示需要重试,is_timeout()方法返回False表示没有超时。当my_function在5次尝试中仍然抛出异常时,它将尝试最多6次,每次等待1到2秒之间随机的时间。如果my_function在5次尝试中仍然抛出异常,它将会在后续尝试中被重新调用。
下面是一个使用retrying实现自定义重试策略的例子:
from retrying import retry
@retry(wait_between=10)
def download_file(url):
try:
response = requests.get(url)
return response.content
except Exception as e:
print(f"Error downloading file: {e}")
return None
在这个例子中,我们定义了一个名为download_file的函数,它接受一个URL作为参数,并尝试从该URL下载文件。如果下载过程中发生错误,函数将返回None。如果下载成功,函数将返回文件的二进制内容。
我们使用@retry装饰器来定义一个自定义的重试策略。在这个例子中,我们使用了wait_between参数来指定每次重试之间的等待时间。这个参数的默认值为10秒。如果下载过程中发生错误,retrying将尝试重新下载文件,最多重试5次。如果下载成功,函数将返回文件的二进制内容。如果下载失败,函数将返回None。
需要注意的是,retrying库中的重试策略是固定的,无法根据具体情况进行调整。如果需要更灵活的重试策略,可以考虑使用其他库,例如Retrying、treq等。
retrying模块中的Retrying类提供了以下方法:
- @retrying(stop_max_attempt_number=10, wait_fixed=100):装饰器形式的重试策略,可以设置最大重试次数和每次重试的等待时间。
- Retrying(stop_max_attempt_number=10, wait_fixed=100):类形式的重试策略,可以设置最大重试次数和每次重试的等待时间。
下面是一个示例代码,演示如何使用retrying模块实现自定义的重试策略:
import time
from retrying import Retrying
# 定义一个可重试函数
def request_api(url, method='get', params=None):
# 模拟网络请求的失败和成功操作
print('request:', url, method)
time.sleep(2) # 模拟网络请求失败
return 'success'
# 定义一个自定义的重试策略
def custom_retry_strategy(exception):
# 判断是否是网络请求失败导致的异常
if isinstance(exception, ConnectionError):
return True
return False
# 创建自定义的重试策略对象
retrying = Retrying(stop_max_attempt_number=3, wait_fixed=100)
custom_retry = retrying(custom_retry_strategy)
# 调用可重试函数并重试三次,最多只执行三次
try:
response = custom_retry(request_api, url='https://example.com/api', method='post', params={'key': 'value'})
print('response:', response)
except Exception as e:
print('error:', e)
在上面的示例代码中,我们定义了一个可重试函数request_api,它模拟了一个网络请求的操作。然后,我们定义了一个自定义的重试策略custom_retry_strategy,用于判断是否是网络请求失败导致的异常。最后,我们创建了一个自定义的重试策略对象custom_retry,并使用它来调用可重试函数request_api,最多只执行三次。如果发生异常,将会进行三次重试,直到成功为止。
最大重试次数
from retrying import retry
@retry(stop_max_attempt_number=5)
def do_something_limited():
print("do something several times")
raise Exception("raise exception")
do_something_limited()
限制最长重试时间(从执行方法开始计算)
from retrying import retry
@retry(stop_max_delay=5000)
def do_something_in_time():
print("do something in time")
raise Exception("raise exception")
do_something_in_time()
设置固定重试时间
from retrying import retry
@retry(wait_fixed=2000)
def wait_fixed_time():
print("wait")
raise Exception("raise exception")
wait_fixed_time()
设置重试时间的随机范围
from retrying import retry
@retry(wait_random_min=1000, wait_random_max=2000)
def wait_random_time():
print("wait")
raise Exception("raise exception")
wait_random_time()
retry_on_exception
参数
# 自己定义一个函数,判断异常类型,然后将函数作为参数传给装饰函数 retry ,如果异常类型符合,就会进行重试。
from retrying import retry
# 根据异常重试
def retry_if_io_error(exception):
return isinstance(exception, IOError)
# 设置特定异常类型重试
@retry(retry_on_exception=retry_if_io_error)
def retry_special_error():
print("retry io error")
raise IOError("raise exception")
retry_special_error()
retry_on_result
参数
# 定义了一个判断返回值的函数,然后将这个函数作为参数传给 retry 装饰函数。当结果返回是“111”时,就会一直重试执行 might_return_none 函数。
from retrying import retry
# 通过返回值判断是否重试
def retry_if_result_none(result):
"""Return True if we should retry (in this case when result is None), False otherwise"""
# return result is None
if result == "111":
return True
@retry(retry_on_result=retry_if_result_none)
def might_return_none():
print("Retry forever ignoring Exceptions with no wait if return value is None")
return "111"
might_return_none()