【问题标题】:Best practices in repeating request if request failed?如果请求失败,重复请求的最佳实践?
【发布时间】:2021-03-31 16:43:51
【问题描述】:

我很好奇在 Python3 中使用 requests 库重复失败请求的最佳实践。我有一个简单的 API 包装器,它向构造的 URL 发出 get 请求。如果requests 引发异常,我想在引发异常之前重试请求。

我不确定是否有一些我不知道的标准做法。我所拥有的会将请求重复 10 倍,将每次迭代中请求之间的等待时间加倍。

import time
import requests
from requests.exceptions import RequestException


def get_request(*args, max_retry=10, **kwargs):
    """ Gets requests.models.Response object using requests.get.
    Retry request if request fails, with number of iteration specified
    by max_retry. """

    def recurse_get_request(*args, retries=0, wait=0.005, **kwargs):
        try:
            return requests.get(*args, **kwargs)
        except RequestException as exc:
            if retries > max_retry:
                raise RequestException from exc

            print("Request failed: (%s). Retrying after %s seconds ..." % (exc, "%.2f" % wait))
            time.sleep(wait)
            # double the wait time after every iteration
            wait *= 2
            retries += 1
            return recurse_get_request(*args, retries=retries, wait=wait, **kwargs)

    return recurse_get_request(*args, **kwargs)


get_request('https://sfbay.craigs.org')  # bad url

【问题讨论】:

  • 加倍请求之间的时间(或一般exponential increase in delay)是我所知道的最佳实践(您也可以添加抖动)。您应该查看 tenacity 库以使用装饰器重试请求。
  • 恕我直言,没关系,这是一种标准程序。但是为什么要让它递归而不是 for 循环呢?很难理解发生了什么。我也会尽量延长等待时间。否则在 max_retry=20 时,已经需要 1.5 小时

标签: python python-3.x python-requests urllib


【解决方案1】:

你所拥有的是truncated exponential backoff,它已经相当不错了。之所以称为“截断”,是因为它最终会停止重试并完全放弃。

维基百科上的链接描述也实现了随机化,我称之为截断随机化指数退避。如果只有一个客户端,则不需要随机化,但如果有多个客户端使用相同的退避计划竞争相同的资源,您可能会遇到thundering herd problem。随机化有助于避免这种情况。

Python 包Tenacity 可帮助您通过一个不错的不显眼的装饰器轻松实现这一切。这是我如何使用它的示例:

import tenacity

# Retry 10 times, starting with 1 second and doubling the delay every time.
_RETRY_ARGS = {
    'wait': tenacity.wait.wait_random_exponential(multiplier=1.0, exp_base=2),
    'stop': tenacity.stop.stop_after_attempt(10)
}

@tenacity.retry(**_RETRY_ARGS)
def something_that_might_fail():
    ...

@tenacity.retry(**_RETRY_ARGS)
def something_else_that_might_fail():
    ...

【讨论】:

    猜你喜欢
    • 2020-11-20
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多