一、介绍
tenacity 和 retrying 都是 Python 中常用的重试库,用于实现在出现异常或特定条件下进行自动重试的功能。它们具有类似的目标,但在实现和使用上有一些区别。
- retrying:
- retrying 是一个简单而强大的重试库,提供了 @retry 装饰器来修饰函数或方法,实现自动重试的功能。
- retrying 的参数可以灵活配置,可以控制重试的次数、延迟时间、重试条件等。
- retrying 支持多种等待策略,如固定间隔、随机间隔和指数退避等待策略。
- retrying 的官方网站是 https://github.com/rholder/retrying。
- tenacity:
- tenacity 是一个强大且灵活的重试库,提供了多种重试策略和功能。
- tenacity 的主要特点是可以通过自定义的 stop、wait 和 retry 策略来灵活控制重试的行为。
- tenacity 支持多种重试条件,可以基于异常类型、返回值、时间等进行重试。
- tenacity 还提供了一些高级功能,如超时、异步重试、断言等。
- tenacity 的官方网站是 https://github.com/jd/tenacity。
二、安装
pip install tenacity
pip install retrying
三、retrying下的retry
- @retrying.retry(stop_max_attempt_number,stop_max_delay,wait_fixed,wait_random_min,wait_random_max,wait_exponential_multiplier,wait_exponential_max,retry_on_exception,wrap_exception,retry_on_result):装饰器,用于修饰函数或方法,实现自动重试
- stop_max_attempt_number:指定重试的最大次数。当达到最大重试次数后,停止重试。默认值为 5。
- stop_max_delay:指定重试的最大总延迟时间(毫秒)。当重试的总延迟时间超过该值时,停止重试。默认值为 None,表示没有最大延迟时间限制。
- wait_fixed:指定重试的固定间隔时间(毫秒)。在每次重试之间等待固定的时间间隔。默认值为 None,表示没有固定间隔时间,而是使用其他的等待策略。
- wait_random_min 和 wait_random_max:指定重试的随机间隔时间范围(毫秒)。在每次重试之间等待一个随机的时间间隔,范围为 [wait_random_min, * * wait_random_max]。默认值为 None,表示没有随机间隔时间,而是使用其他的等待策略。
- wait_exponential_multiplier 和 wait_exponential_max:指定指数退避等待策略的参数。wait_exponential_multiplier 表示每次重试的等待时间将乘以的倍数,wait_exponential_max 表示重试的等待时间的最大值。默认值为 None,表示不使用指数退避等待策略。
- retry_on_exception:指定在哪些异常发生时进行重试。可以是一个异常类型或异常类型的元组。默认值为 True,表示在任何异常发生时都进行重试。
- wrap_exception:指定是否将重试期间捕获的异常包装在一个特定的异常类型中。默认值为 False,表示不进行异常包装。
- retry_on_result:指定在哪些返回值情况下进行重试。可以是一个函数,当函数返回 True 时触发重试。默认值为 False,表示不根据返回值情况进行重试。
四、tenacity中的retry
- @tenacity.retry(stop,wait,retry,reraise,before,after,before_sleep,retry_error_callback,sleep):装饰器,用于修饰函数或方法,实现自动重试
- stop:停止策略,用于定义何时停止重试的条件,停止策略函数,tenacity.stop或者自定义函数。
- wait:等待策略,用于定义重试之间的等待时间,等待策略函数,tenacity.wait或者自定义函数。
- retry:重试条件,用于定义触发重试的条件,tenacity.retry或者自定义函数。
- reraise:布尔值,表示是否重新引发最后一次异常。
- before:在每次重试之前执行的操作,指定一个函数t,enacity.before。
- after:在每次重试之后执行的操作,指定一个函数,tenacity.after。
- before_sleep:在等待之前执行的操作,指定一个函数,tenacity.before_sleep或者自定义函数。
- retry_error_callback:重试错误回调函数,用于处理重试过程中的错误,指定一个函数。
- sleep:在重试之前进行睡眠的函数,指定一个函数。
五、停止策略:tenacity.stop
- 自定义函数
import tenacity def stop(retry_state): print(retry_state) return True def retry_if_result_none(retry_state): print(retry_state) return True @tenacity.retry(retry=retry_if_result_none,stop=stop) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_after_attempt:停止策略,当重试次数达到指定次数时停止重试。
import tenacity def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop=tenacity.stop.stop_after_attempt(3)) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_after_delay:停止策略,当重试持续时间达到指定时间时停止重试。
import tenacity def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop=tenacity.stop.stop_after_delay(2)) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_all:停止策略,要求所有停止条件都满足才停止重试。
import tenacity import time stop_policy = tenacity.stop.stop_all( tenacity.stop.stop_after_attempt(10), tenacity.stop.stop_after_delay(2) ) def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop=stop_policy) def my_function(): time.sleep(1) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_any:停止策略,只要有任何一个停止条件满足就停止重试。
import tenacity import time stop_policy = tenacity.stop.stop_any( tenacity.stop.stop_after_attempt(10), tenacity.stop.stop_after_delay(2) ) def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop=stop_policy) def my_function(): time.sleep(1) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_never:停止策略,永不停止重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop = tenacity.stop.stop_never) def my_function(): time.sleep(1) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_when_event_set:停止策略,当指定事件被设置时停止重试。
import tenacity import threading stop_event = threading.Event() stop_policy = tenacity.stop.stop_when_event_set(stop_event) def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,stop = stop_policy) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.stop.stop_base:基类停止策略,用于自定义停止策略。
六、等待策略:tenacity.wait
- 自定义函数
import tenacity import time def wait_fun(retry_state): print(retry_state) time.sleep(2) return True def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=wait_fun) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_fixed:等待策略,固定等待一段时间后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_fixed(2)) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_none:等待策略,无需等待,立即进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_none()) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_incrementing:等待策略,递增地等待一段时间后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_incrementing(2)) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_chain:等待策略,按照指定的等待策略链依次进行等待。
import tenacity import time wait_chain = tenacity.wait.wait_chain( tenacity.wait.wait_fixed(2), tenacity.wait.wait_incrementing(2) ) def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=wait_chain) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_combine:等待策略,将多个等待策略组合在一起,按照指定的组合方式进行等待。
import tenacity import time wait_combine = tenacity.wait.wait_combine( tenacity.wait.wait_fixed(2), tenacity.wait.wait_incrementing(2) ) def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=wait_combine) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_exponential:等待策略,指数增长地等待一段时间后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_exponential(3)) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_exponential_jitter:等待策略,指数增长地等待一段时间,并加入随机抖动后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_exponential_jitter(3)) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_random:等待策略,随机等待一段时间后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_random()) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_random_exponential:等待策略,随机指数增长地等待一段时间后再进行重试。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,wait=tenacity.wait.wait_random_exponential()) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.wait.wait_base:基类等待策略,用于自定义等待策略。
七、重试条件:tenacity.retry
- 自定义函数
import tenacity def retry_if_result_none(retry_state): return retry_state is None #返回True,则重试 @tenacity.retry(retry=retry_if_result_none) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.retry_always:条件函数,始终进行重试,无论条件如何
import tenacity @tenacity.retry(retry=tenacity.retry_always) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.retry_never:条件函数,永不重试。
import tenacity @tenacity.retry(retry=tenacity.retry_never) def my_function(): print('重试代码') #返回True,则重试 # 调用被装饰的函数 my_function()
- tenacity.retry_if_result:条件函数,只有当函数返回指定值时才进行重试。
import tenacity def check_result(retry_state): return True @tenacity.retry(retry=tenacity.retry_if_result(check_result)) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.retry_if_not_result:条件函数,只有当函数返回指定值时才不进行重试。
import tenacity def check_result(retry_state): return False @tenacity.retry(retry=tenacity.retry_if_not_result(check_result)) def my_function(): print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.retry_if_exception:条件函数,只有当抛出指定类型的异常时才进行重试。
import tenacity import random @tenacity.retry(retry=tenacity.retry_if_exception(Exception)) def my_function(): nu = random.randint(1,10) try: if nu<5: raise Exception(f'报错,需要重试={nu}') else: print(f'重试结束={nu}') except Exception as e: # 处理异常 print("错误信息:", e) raise my_function()
- tenacity.retry_if_exception_type:条件函数,只有当抛出指定类型的异常时才进行重试。
import tenacity import random @tenacity.retry(retry=tenacity.retry_if_exception_type(Exception)) def my_function(): nu = random.randint(1,10) try: if nu<5: raise Exception(f'报错,需要重试={nu}') else: print(f'重试结束={nu}') except Exception as e: # 处理异常 print("错误信息:", e) raise my_function()
- tenacity.retry_if_exception_type:条件函数,只有当抛出指定类型的异常时才进行重试。
import tenacity import random @tenacity.retry(retry=tenacity.retry_if_not_exception_type(Exception)) def my_function(): nu = random.randint(1,10) try: if nu<5: raise Exception(f'报错,不需要重试={nu}') else: print(f'重试结束={nu}') except Exception as e: # 处理异常 print("错误信息:", e) raise my_function()
- tenacity.retry_unless_exception_type:装饰器,除非抛出指定类型的异常,否则进行重试。
import tenacity import random @tenacity.retry(retry=tenacity.retry_unless_exception_type(Exception)) def my_function(): nu = random.randint(1,10) try: if nu<5: raise Exception(f'报错,不需要重试={nu}') else: print(f'重试结束={nu}') except Exception as e: # 处理异常 print("错误信息:", e) raise my_function()
- tenacity.retry_any:条件函数,只要有任何一个条件函数返回 True,就进行重试。
- tenacity.retry_all:条件函数,要求所有条件函数都返回 True 才进行重试。
- tenacity.retry_if_exception_message:条件函数,只有当抛出指定异常消息的异常时才进行重试。
- tenacity.retry_if_not_exception_message:条件函数,只有当未抛出指定异常消息的异常时才进行重试。
- tenacity.retry_if_exception_cause_type:条件函数,只有当异常的原因是指定类型的异常时才进行重试。
八、重试之前执行的操作:tenacity.before
- tenacity.before.before_log:前置操作,用于在每次重试之前记录日志信息。
import tenacity import time from loguru import logger def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,before=tenacity.before.before_log(logger, 'INFO')) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
- tenacity.before.before_nothing:前置操作,不执行任何操作,即无操作。
import tenacity import time def retry_if_result_none(retry_state): return True @tenacity.retry(retry=retry_if_result_none,before=tenacity.before.before_nothing) def my_function(): print(time.time()) print('重试代码') # 调用被装饰的函数 my_function()
九、重试之后执行的操作:tenacity.after
- tenacity.after.after_log:后置操作,用于在每次重试之后记录日志信息。
- tenacity.after.after_nothing:后置操作,不执行任何操作,即无操作。
- tenacity.after.RetryCallState:重试调用状态对象,用于在重试过程中跟踪状态和信息。
十、等待之前执行的操作:tenacity.before_sleep
- tenacity.before_sleep.before_sleep_log:睡眠前操作,用于在每次重试之前记录日志信息。
- tenacity.before_sleep.before_sleep_nothing:睡眠前操作,不执行任何操作,即无操作。
十一、控制重试之间的等待时间:tenacity.nap
- tenacity.nap.sleep:这是 tenacity 库中默认的睡眠函数。它使用标准的时间模块进行睡眠,即使用 time.sleep 函数。
- tenacity.nap.sleep_using_event:这是另一种睡眠函数,它使用 eventlet 或 gevent 等协程库来实现睡眠。这种睡眠函数适用于在协程环境中使用 tenacity 库。
十二、重试状态对象:RetryCallState
- tenacity.RetryCallState():创建的 RetryCallState 实例
- attempt_number:返回当前重试的次数(从1开始计数)。
- delay_since_first_attempt:返回从首次重试开始经过的时间(以秒为单位)。
- start_time:返回首次重试的时间戳(以秒为单位)。
- outcome:返回最后一次重试的结果。如果重试尚未完成或未成功,该值为 None。
- last_exception:返回最后一次重试时引发的异常。如果重试尚未完成或未引发异常,该值为 None。
- initialize_time():将 start_time 设置为当前时间。
- initialize_outcome(result):将 outcome 设置为给定的 result。
- initialize_exception(exception):将 last_exception 设置为给定的 exception。
- get_elapsed_time():返回从首次重试开始经过的时间(以秒为单位)。
- get_attempt_number():返回当前重试的次数。
- get_last_result():返回最后一次重试的结果。
- get_last_exception():返回最后一次重试时引发的异常。