处理(排队)对呼叫速率受限的外部API的Web服务的请求

Ami*_*mar 5 python webserver web-services rate-limiting flask

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

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

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

有没有一种方法可以将请求排队到我的Web服务,然后以限制方式调用外部API.

任何其他想法也受到欢迎.


编辑:

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

  2. 如果请求我的API的客户端在获得结果之前必须等待一段时间(几秒钟/几分钟,具体取决于我的负载),我没关系.

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

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

Bre*_*bel 2

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

在下面的示例中,它将不断重试请求,直到成功为止,每次失败时,请求之间的等待时间会越来越长,直到达到允许的重试最大次数 ( 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
Run Code Online (Sandbox Code Playgroud)