我目前正在使用Google的BigQuery API,它在调用时偶尔会给我:
apiclient.errors.HttpError: <HttpError 500 when requesting https://www.googleapis.com/bigquery/v2/projects/some_job?alt=json returned "Unexpected. Please try again.">
Run Code Online (Sandbox Code Playgroud)
返回是一件很愚蠢的事情,但无论如何,当我为任何一种方法得到这个时,我只想睡一两秒然后再试一次.基本上,我想用以下方法包装每个方法:
def new_method
try:
method()
except apiclient.errors.HttpError, e:
if e.resp.status == 500:
sleep(2)
new_method()
else:
raise e
Run Code Online (Sandbox Code Playgroud)
这样做的好方法是什么?
我不想显式重新定义类中的每个方法.我只是想自动将一些东西应用到课堂上的每一个方法中,所以我对未来有所了解.理想情况下,我会采取一个类的对象,O,并围绕它的包装,重新定义每个方法的类此尝试不同的包装,所以我得到了一些新的对象,P,当它得到一个500错误自动重试.
装饰师是完美的.您可以使用像这样的装饰器来装饰每个相关方法:
(注意使用递归进行重试可能不是一个好主意...)
def Http500Resistant(func):
num_retries = 5
@functools.wraps(func)
def wrapper(*a, **kw):
sleep_interval = 2
for i in range(num_retries):
try:
return func(*a, **kw)
except apiclient.errors.HttpError, e:
if e.resp.status == 500 and i < num_retries-1:
sleep(sleep_interval)
sleep_interval = min(2*sleep_interval, 60)
else:
raise e
return wrapper
class A(object):
@Http500Resistant
def f1(self): ...
@Http500Resistant
def f2(self): ...
Run Code Online (Sandbox Code Playgroud)
要自动将装饰器应用于所有方法,您可以使用yet-another-decorator,这次,装饰类:
import inspect
def decorate_all_methods(decorator):
def apply_decorator(cls):
for k, f in cls.__dict__.items():
if inspect.isfunction(f):
setattr(cls, k, decorator(f))
return cls
return apply_decorator
Run Code Online (Sandbox Code Playgroud)
并像这样申请:
@decorate_all_methods(Http500Resistant)
class A(object):
...
Run Code Online (Sandbox Code Playgroud)
或者像:
class A(object): ...
A = decorate_all_methods(Http500Resistant)(A)
Run Code Online (Sandbox Code Playgroud)