使用场景:
比如在调用网络API时,提高成功率。
import requests from datetime import datetime import time import random retry_timeout = 10 def http_request(url, first_request_time=None, retry_counter=0): """ first_request_time: The time of the first request (None if no retries have occurred). retry_counter: The number of this retry, or zero for first attempt. """ if not first_request_time: first_request_time = datetime.now() try: elapsed = datetime.now() - first_request_time if elapsed.total_seconds() > retry_timeout: raise TimeoutError if retry_counter > 0: # 0.5 * (1.5 ^ i) is an increased sleep time of 1.5x per iteration, # starting at 0.5s when retry_counter=0. The first retry will occur # at 1, so subtract that first. delay_seconds = 0.5 * 1.5**(retry_counter - 1) print(f"Delay {delay_seconds}") # Jitter this value by 50% and pause. time.sleep(delay_seconds * (random.random() + 0.5)) result = requests.get(url) return result.text except TimeoutError: print("Request Timed out") return None except requests.exceptions.ConnectionError: return http_request(url, first_request_time, retry_counter + 1) if __name__ == "__main__": response_text = http_request("https://thissitedoesntexist.com") # retries the request to an invalid url until the timeout of 10 second is reached # A TimeoutError is raised after 10 seconds
这个实现一般就够用了,再复杂一点,有专门的backoff退避算法。
1 import time 2 from functools import wraps 3 4 5 def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None): 6 """Retry calling the decorated function using an exponential backoff. 7 8 http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/ 9 original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry 10 11 :param ExceptionToCheck: the exception to check. may be a tuple of 12 exceptions to check 13 :type ExceptionToCheck: Exception or tuple 14 :param tries: number of times to try (not retry) before giving up 15 :type tries: int 16 :param delay: initial delay between retries in seconds 17 :type delay: int 18 :param backoff: backoff multiplier e.g. value of 2 will double the delay 19 each retry 20 :type backoff: int 21 :param logger: logger to use. If None, print 22 :type logger: logging.Logger instance 23 """ 24 def deco_retry(f): 25 26 @wraps(f) 27 def f_retry(*args, **kwargs): 28 mtries, mdelay = tries, delay 29 while mtries > 1: 30 try: 31 return f(*args, **kwargs) 32 except ExceptionToCheck, e: 33 msg = "%s, Retrying in %d seconds..." % (str(e), mdelay) 34 if logger: 35 logger.warning(msg) 36 else: 37 print msg 38 time.sleep(mdelay) 39 mtries -= 1 40 mdelay *= backoff 41 return f(*args, **kwargs) 42 43 return f_retry # true decorator 44 45 return deco_retry
来源:https://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/