处理(排队)对Web服务的请求,该服务调用速率受限的外部API

时间:2016-02-08 05:25:41

标签: python web-services flask webserver rate-limiting

我使用Flask框架公开了一个Web服务。

此服务用作外部API,对每秒应调用的次数有限制。

在正常情况下,对我的API的多次调用会导致生成多个线程,并且在不对每秒请求数进行任何控制的情况下调用外部API。

是否有一种方法可以将请求排入Web服务,然后以限制方式调用外部API。

欢迎任何其他想法。

编辑:

  1. 我已经知道外部API的费率(每秒1个请求)

  2. 如果请求我的API的客户端在获得结果之前需要等待一段时间(几秒钟/分钟,具体取决于我的负载),我会好的。

  3. 我不希望我的API客户端获得失败的结果。即我不希望他们一次又一次地打电话。如果我已经以尽可能最大的速率访问外部API,那么当速率降低时,对我的API的请求应该排队并处理。

  4. 我读到了CeleryRedis。我是否可以将Web服务调用排入这些队列并稍后处理它们?

1 个答案:

答案 0 :(得分:1)

一种方法是包装请求,以便速率限制失败将导致指数退避,直到找到可接受的速率。

在下面的示例中,它将继续重试请求,直到成功,每次失败时请求之间的等待时间越来越长,最多允许的重试次数(n_max)。等待重试请求的秒数呈指数级增长(1,2,4,8,16,32等)。

以下是使用requests的示例。捕获错误和识别速率限制错误的细节取决于您用于发出请求的库以及外部api返回的错误类型,但退避算法应该是相同的。

def call_backoff(request_func, n_max=10):
    n = 0
    while n < n_max:
        error = False
        try:
            response = request_func()
        except errors.HttpError as e:
            # You can test here if this is a rate error
            # and not some other error.  You can decide how to handle
            # other errors.
            error = True
            if not_a_rate_error:
                raise

         if response.status_code == 429:
             error = True

         if not error:
             return response

         milli = random.randint(1, 1000)
         secs = (2 ** n) + milli / 1000.0
         time.sleep(secs)
         n += 1

    # You can raise an error here if you'd like
    return None