• Tenacity 实现"重试机制"


    1.tenacity有什么用?

      Tenacity是一个通用的retry库,简化为任何任务加入重试的功能。

      它还包含如下特性:

    •     通用的装饰器API
    •     可以设定重试停止的条件(比如设定尝试次数)
    •     可以设定重试间的等待时间(比如在尝试之间使用幂数级增长的wait等待)
    •     自定义在哪些Exception进行重试
    •     自定义在哪些返回值的情况进行重试
    •     协程的重试

    2.为什么使用tenacity

    很多时候,我们都喜欢为代码加入retry功能。比如oauth验证,有时候网络不太灵,我们希望多试几次。这些retry应用的场景看起来不同,其实又很类似。都是判断代码是否正常运行,如果不是则重新开始。那么,有没有一种通用的办法来实现呢?

    3.使用介绍

      1)简单的使用方法,是直接给需要重试的代码加上@retry修饰器,代码抛出异常会被装饰器捕获并进行重试,异常抛出时会不断重试直到代码执行成功

    from tenacity import retry
    
    import requests
    
    @retry
    def conn_req():
        response = requests.get(url="http://www.baidu.com")
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = conn_req()
    print(res)

      

      2)加上终止条件的retry

    • 给retry加上一个参数,让它重试3次后不再重试并抛出异常
    rom tenacity import retry,stop_after_attempt
    
    import requests
    
    @retry(stop=stop_after_attempt(3))
    def conn_req():
        response = requests.get(url="http://www.baibai.com")
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = conn_req()
    print(res)

     

    • 使用@stop_after_delay重试 5 秒后不再重试
    from tenacity import retry,stop_after_attempt,stop_after_delay
    
    import requests
    
    @retry(stop=stop_after_delay(5))
    def conn_req():
        response = requests.get(url="http://www.baibai.com")
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = conn_req()
    print(res)

      

    • 同时可以使用“|”把多个条件进行组合使用,两个条件满足一个就结束重试,抛出异常
    from tenacity import retry, stop_after_delay, stop_after_attempt
    import requests
    
    @retry(stop=stop_after_delay(5) |stop_after_attempt(5))
    def stop_after_5_s():
        response = requests.get(url='http://www.baidu.com')
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = stop_after_5_s()
    print(res)

      3)代码重试前等待间隔

        

    • 使用@wait_fixed在程序重试前等待固定时间,下面就是每隔2秒进行重试
    from tenacity import retry, wait_fixed
    import requests
    
    @retry(wait=wait_fixed(2))
    def wait_2_s():
        response = requests.get(url='http://www.baibai.com')
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = wait_2_s()
    print res

      

    • 使用@wait_random随机等待,主要应用爬虫的场景比较多
    from tenacity import retry, wait_random
    import requests
    
    @retry(wait=wait_random(min=1, max=2))
    def wait_2_s():
        response = requests.get(url='http://www.baibai.com')
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = wait_2_s()
    print res

      

    • 使用@wait_exponential可以按照指数的等待时间
    from tenacity import retry, wait_exponential
    import requests
    
    @retry(wait=wait_exponential(multiplier=2, min=3, max=100))    # 重试时间间隔满足:2^n * multiplier, n为重试次数,但最多间隔10秒
    def wait_2_s():
        response = requests.get(url='http://www.baibai.com')
        if response.status_code == 200:
            return response.text
        raise Exception
    
    res = wait_2_s()
    print res

      4)带有触发条件的retry语句

    from tenacity import retry, retry_if_exception_type, retry_if_result
    
    @retry(retry=retry_if_exception_type(IOError))
    def might_io_error():
        print("Retry forever with no wait if an IOError occurs, raise any other errors")
        raise Exception
    
    def is_none_p(value):
        """Return True if value is None"""
        return value is None
    
    @retry(retry=retry_if_result(is_none_p))
    def might_return_none():
        print("Retry with no wait if return value is None")
        
    @retry(retry=(retry_if_result(is_none_p) | retry_if_exception_type()))
    def might_return_none():
        print("Retry forever ignoring Exceptions with no wait if return value is None")

      5)在retry前后增加log

    ty import retry, stop_after_attempt, before_log, after_log, before_sleep_log
    import logging
    
    logger = logging.getLogger(__name__)
    
    
    @retry(stop=stop_after_attempt(3), before=before_log(logger, logging.DEBUG))
    def raise_my_exception():
        raise MyException("Fail")
    
    
    @retry(stop=stop_after_attempt(3), after=after_log(logger, logging.DEBUG))
    def raise_my_exception():
        raise MyException("Fail")
    
    
    @retry(stop=stop_after_attempt(3),
           before_sleep=before_sleep_log(logger, logging.DEBUG))
    def raise_my_exception():
        raise MyException("Fail")

       6)重试后错误重新抛出

        当出现异常后,tenacity 会进行重试,若重试后还是失败,默认情况下,往上抛出的异常会变成 RetryError,而不是最根本的原因。

    因此可以加一个参数(reraise=True),使得当重试失败后,往外抛出的异常还是原来的那个。

    from tenacity import retry, stop_after_attempt
    
    @retry(stop=stop_after_attempt(7), reraise=True)
    def test_retry():
        print("等待重试...")
        raise Exception
    
    test_retry()

      7)设置回调函数

        当最后一次重试失败后,可以执行一个回调函数

    from tenacity import *
    
    def return_last_value(retry_state):
        print("执行回调函数")
        return retry_state.outcome.result()  # 表示返回原函数的返回值
    
    def is_false(value):
        return value is False
    
    @retry(stop=stop_after_attempt(3),
           retry_error_callback=return_last_value,
           retry=retry_if_result(is_false))
    def test_retry():
        print("等待重试中...")
        return False
    
    print(test_retry())

    转自:https://blog.csdn.net/qq_37287621/article/details/95055718

  • 相关阅读:
    Holiday、Vacation、Days off、Leave、Break
    python3对urllib和urllib2进行了重构
    python解析json
    NeuHub图像垃圾分类api和百度图像识别api
    base64加密与解密
    wafer2的keng
    HTTP 中 GET 与 POST 的区别
    如何禁用Antimalware Service Executable
    通过SimpleHTTPServer实现树莓派与主机传输文件
    电脑通过网线连接树莓派
  • 原文地址:https://www.cnblogs.com/tjp40922/p/14127429.html
Copyright © 2020-2023  润新知