我可以为requests.request设置max_retries吗?
Python请求模块简单而优雅,但有一点让我感到困扰。 有可能得到一个requests.exception.ConnectionError消息,如:
Max retries exceeded with url: ...
这意味着请求可以尝试多次访问数据。 但是在文档的任何地方都没有提到这种可能性。 看看源代码,我没有find任何地方可以改变默认值(大概为0)。
那么是否有可能以某种方式设置请求的最大重试次数?
这是底层urllib3
库urllib3
。 要设置不同的最大重试次数,请使用其他传输适配器 :
from requests.adapters import HTTPAdapter s = requests.Session() s.mount('http://stackoverflow.com', HTTPAdapter(max_retries=5))
max_retries
参数采用整数或Retry()
对象 ; 后者给你细粒度的控制什么样的失败重试(一个整数值变成一个Retry()
实例,只处理连接失败;连接后的错误默认不处理,因为这些可能导致侧效果 – )。
旧答案,早于请求的发布1.2.1 :
requests
库并不真正使这个可configuration,也不打算(见这个拉请求 )。 当前(请求1.1),重试计数设置为0.如果您确实想将其设置为更高的值,则必须全局设置:
import requests requests.adapters.DEFAULT_RETRIES = 5
这个常数没有logging。 因为未来的版本可能会改变这种处理方式,所以可以自己使用。
更新 :这确实改变了; 在版本1.2.1中,添加了在HTTPAdapter()
类上设置max_retries
参数的选项 ,因此现在必须使用其他传输适配器,请参阅上文。 除非你也修补了HTTPAdapter.__init__()
默认值(非常不推荐),所以这个monkey-patch方法不再适用。
这不仅会改变max_retries,而且还会启用一个退避策略,使得对所有http://地址的请求在重试前hibernate一段时间(总共5次):
import requests from requests.packages.urllib3.util.retry import Retry from requests.adapters import HTTPAdapter s = requests.Session() retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[ 500, 502, 503, 504 ]) s.mount('http://', HTTPAdapter(max_retries=retries)) s.get('http://httpstat.us/500')
根据Retry的文档 :如果backoff_factor是0.1,那么sleep()将在重试之间hibernate[0.1s,0.2s,0.4s,…]。 如果返回的状态码是500,502,503或504,它也会强制重试。
重试的各种其他选项允许更精细的控制:
- 总数 – 允许的重试次数。
- 连接 – 重试多less与连接相关的错误。
- 读取 – 读取错误重试多less次。
- redirect – 执行多less个redirect。
- method_whitelist – 我们应该重试的一组大写的HTTP方法动词。
- status_forcelist – 我们应该强制重试的一组HTTP状态代码。
- backoff_factor – 尝试之间应用的退避因子。
- raise_on_redirect – redirect的数量是否用尽,引发MaxRetryError,或返回响应代码在3xx范围内的响应。
- raise_on_status – 类似的意思raise_on_redirect:是否应该引发一个exception,或者返回一个响应,如果状态落在status_forcelist范围内并且重试已经用尽。
注意 : raise_on_status是比较新的,并没有成为urllib3或请求的发布。
要使请求在特定的HTTP状态码上重试,请使用status_forcelist。 例如,status_forcelist = [503]将在状态码503(服务不可用)上重试。
默认情况下,仅针对以下情况触发重试:
- 无法从游泳池获得连接。
- TimeoutError
- 引发HTTPException(从Python 3中的http.client else httplib)。 这似乎是低级别的HTTPexception,如URL或协议未正确形成。
- SocketError
- 协议错误
请注意,这些都是防止收到常规HTTP响应的所有exception。 如果生成任何常规响应,则不会执行重试。 在不使用status_forcelist的情况下,即使是状态为500的响应也不会被重试。
为了使它的行为方式对于使用远程API或Web服务器更加直观,我将使用上面的代码片断,这将强制对状态500,502,503和504进行重试,所有这些在代码片段中都是不常见的networking和(可能)回收足够大的回退期。
要小心,Martijn Pieters的答案不适用于1.2.1+版本。 如果不修补库,则无法全局设置。
你可以这样做:
import requests from requests.adapters import HTTPAdapter s = requests.Session() s.mount('http://www.github.com', HTTPAdapter(max_retries=5)) s.mount('https://www.github.com', HTTPAdapter(max_retries=5))
获得更高控制的一个更简洁的方法可能是将重试的东西封装到一个函数中,并使用装饰器使该函数可回溯,并将例外列入白名单。
我在这里创造了同样的: http : //www.praddy.in/retry-decorator-whitelisted-exceptions/
重现该链接中的代码:
def retry(exceptions, delay=0, times=2): """ A decorator for retrying a function call with a specified delay in case of a set of exceptions Parameter List ------------- :param exceptions: A tuple of all exceptions that need to be caught for retry eg retry(exception_list = (Timeout, Readtimeout)) :param delay: Amount of delay (seconds) needed between successive retries. :param times: no of times the function should be retried """ def outer_wrapper(function): @functools.wraps(function) def inner_wrapper(*args, **kwargs): final_excep = None for counter in xrange(times): if counter > 0: time.sleep(delay) final_excep = None try: value = function(*args, **kwargs) return value except (exceptions) as e: final_excep = e pass #or log it if final_excep is not None: raise final_excep return inner_wrapper return outer_wrapper @retry(exceptions=(TimeoutError, ConnectTimeoutError), delay=0, times=3) def call_api():
我在这里find了一些答案后,发现了一个名为backoff的库,对我的情况更好。 一个基本的例子:
import backoff @backoff.on_exception( backoff.expo, requests.exceptions.RequestException, max_tries=5, giveup=lambda e: e.response is not None and e.response.status_code < 500 ) def publish(self, data): r = requests.post(url, timeout=10, json=data) r.raise_for_status()
我仍然build议给图书馆的本地function一个镜头,但如果遇到任何问题或需要更广泛的控制,退避是一种select。