如果请求失败,重复请求的最佳实践?

Best practices in repeating request if request failed?

我很好奇使用 Python3 中的 requests 库重复失败请求的最佳实践。我有一个简单的 API 包装器,它向构造的 URL 发出获取请求。如果 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

你这个叫truncated exponential backoff,已经很不错了。它被称为“t运行cated”,因为它最终会停止重试并完全放弃。

维基百科上的链接描述也实现了随机化,我称之为 t运行cated randomized 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():
    ...