使用场景:
比如在调用网络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/