我的脚本中有多个函数可以执行REST API api请求。由于我需要处理错误情况,我已经设置了如下的重试机制。
no_of_retries = 3
def check_status():
for i in range(0,no_of_retries):
url = "http://something/something"
try:
result = requests.get(url, auth=HTTPBasicAuth(COMMON_USERNAME, COMMON_PASSWORD)).json()
if 'error' not in result:
return result
else:
continue
except Exception as e:
continue
return None
我有几种不同的方法可以进行类似的操作。我们怎样才能更好地避免重复,可能是使用装饰器。
答案 0 :(得分:2)
如果您不介意安装库,可以使用tenacity
(github.com/jd/tenacity)模块。他们的一个例子:
import random
from tenacity import retry, stop_after_attempt
# @retry # retry forever
@retry(stop=stop_after_attempt(3))
def do_something_unreliable():
if random.randint(0, 10) > 1:
raise IOError("Broken sauce, everything is hosed!!!111one")
else:
return "Awesome sauce!"
print(do_something_unreliable())
这也允许您指定要继续重试的尝试次数或秒数。
对于你的情况,这可能看起来像这样(未经测试!):
@retry(stop=stop_after_attempt(3))
def retry_get():
result = requests.get(
url, auth=HTTPBasicAuth(COMMON_USERNAME, COMMON_PASSWORD)).json()
if 'error' not in result:
raise RequestException(result)
答案 1 :(得分:1)
可能更好的解决方案是将请求移动到自己的函数,而不是使用装饰器,而是使用类似于此的结构:
no_of_retries = 3
def make_request(url):
for i in range(0,no_of_retries):
try:
result = requests.get(url, auth=HTTPBasicAuth(COMMON_USERNAME, COMMON_PASSWORD)).json()
if 'error' not in result:
return result
else:
continue
except Exception as e:
continue
return result
def check_status():
result = make_request("http://something/status")
def load_file():
result = make_request("http://something/file")
这样,您可以在封装请求时避免重复代码。如果您要使用装饰器,则需要包装整个load_file()
方法,这将阻止您在此函数中进一步处理请求的结果。
答案 2 :(得分:0)
您可以使用这样的装饰器并处理您自己的异常。
def retry(times, exceptions):
"""
Retry Decorator
Retries the wrapped function/method `times` times if the exceptions listed
in ``exceptions`` are thrown
:param times: The number of times to repeat the wrapped function/method
:type times: Int
:param Exceptions: Lists of exceptions that trigger a retry attempt
:type Exceptions: Tuple of Exceptions
"""
def decorator(func):
def newfn(*args, **kwargs):
attempt = 0
while attempt < times:
try:
return func(*args, **kwargs)
except exceptions:
print(
'Exception thrown when attempting to run %s, attempt '
'%d of %d' % (func, attempt, times)
)
attempt += 1
return func(*args, **kwargs)
return newfn
return decorator
@retry(times=3, exceptions=(ValueError, TypeError))
def foo1():
print('Some code here ....')
print('Oh no, we have exception')
raise ValueError('Some error')
foo1()