当我们写代码自动化测试代码时,由于页面读取、数据刷新等造成的页面元素不稳定,经常需要在执行出错时进行重试,但是对每一个方法都做一个异常处理加重试的话,又会造成代码冗余的情况,DRY(Don’t repeat yourself),这时,可以将重试的逻辑写成装饰器,而这已经有人写好,作为第三方库可以直接使用了,那就是retry。
pip install retry
from retry import retry @retry() def make_trouble(): '''重试直到成功''' @retry(ZeroDivisionError, tries=3, delay=2) def make_trouble(): '''出现ZerodivisionError时重试,在3次重试失败后抛出错误,重试间隔2秒''' @retry((ValueError, TypeError), delay=1, backoff=2) def make_trouble(): '''出现ValueError或TypeError时重试,重试间隔1,2,4,8...秒,直至执行成功''' @retry((ValueError, TypeError), delay=1, backoff=2, max_delay=4) def make_trouble(): '''出现valueError或TypeError时重试,重试间隔1,2,4,4...秒,直至执行成功''' @retry(ValueError, delay=1, jitter=1) def make_trouble(): '''出现ValueError时重试,重试间隔1,2,3,4...秒,直至执行成功'''
def retry(exceptions=Exception, tries=-1, delay=0, max_delay=None, backoff=1, jitter=0, logger=logging_logger): """ :param exceptions: 需要捕获的异常,当发生该异常时进行重试,需捕获多种异常时可以使用元组,默认为Exception. :param tries: 最大重试次数,默认为-1(无限制) :param delay: 初始时间间隔,重试前的等待时间,默认为0 :param max_delay: 最大时间间隔,默认为None(无限制) :param backoff: 时间间隔系数,每次重试将上一次的重试时间乘以该值作为本次间隔时间,默认为1 :param jitter: 额外的等待时间,每次重试将上一次的时间间隔计算backoff后再加上该值,默认为0,需要随机时可以使用元组(最小值, 最大值) :param logger: 发生重试时记录日志的日志句柄,默认为retry.logging_logger,如果为None, 则不记录日志 """
retry库基本上可以覆盖我们大部分的重试需求了,但是它只能给我们提供基于重试次数的限制,如果我们想要基于超时时间的重试,比如在30秒内发生的错误进行重试,它就不行了,需要我们自己来实现,我在下面提供了一个基础版的样例,想要达到retry库的丰富的配置,可以自己进行扩展
import time from decorator import decorator from loguru import logger @decorator def retry(func, *args, **kwargs): end_time = time.time() + 30 while True: try: return func(*args, **kwargs) except Exception as e: timeout = end_time - time.time() * 1000 if timeout <= 0: logger.exception(f'timeout is arrived, raise') raise e logger.warning(f'timeout still remain {timeout} ms, retry...')