有限制地排队 Guzzle 请求

Queuing Guzzle Requests With Limits

我正在使用 Guzzle 6 开发 Laravel 应用程序。很多功能都依赖于 API,我已经为其创建了一个包装器。

我的包装器是一个 class,它在 __construct() 中创建 Guzzle 客户端,并具有各种 public 函数,这些函数 return 响应 Guzzle 请求。

我正在使用的 API 每 10 秒有 40 个请求的限制。我正在缓存内容,因此很少会达到此限制,但我想知道我的应用程序不会在达到此限制时死掉!

关于我的应用程序的一些说明:

所以,我的问题是,我应该如何确保我没有达到这个限制?我的一些想法如下:

我尽量不引起过于自以为是的回应,但我相信可能有比上述更好的 and/or 更简单的方法,或者如果它们是好主意,任何指示或建议都可以太好了。

提前致谢。

没有足够的信息来真正深入研究这个问题,但为了让您开始,好的 API 通常 return 当您超过限制时会收到 429 响应代码。

您可以使用 guzzle 中的 $res->getStatusCode() 来检查这一点,并在用户发出太多请求的速度过快时向用户闪回一条消息。

你能提供更多关于你的应用程序的信息吗?您是在 foreach 循环中发出请求吗?视图是否依赖于来自此 API 的数据?

我个人认为 Guzzle 不应该处理这种情况,但如果您希望 Guzzle 处理它,我会编写一个中间件来检查响应,如果它 return 是速率限制错误(例如状态代码 429) .然后您可以发出自定义错误或等到速率限制结束后再试。然而,这可能会导致较长的响应时间(因为您等待速率限制)。

我不认为 Laravel 队列会更好,因为这会使响应异步可用,并且无论将结果存储在何处,您都必须轮询数据库或缓存。 (当然,如果您不需要立即获得结果,它也可以工作)

如果此第三方服务直接连接到面向用户的界面,我可能会应用相同的速率限制(在您的应用程序代码中)和 return 向用户发送错误消息,而不是等待和自动解析问题。

我也在处理同样的问题,我更喜欢基于回调的架构,其中我的 Client class 控制请求流。目前我正在做睡眠和检查算法。我为我工作,因为我有 3 秒的冷却时间。

我使用 Cache 来保存触发请求的计数。

while(($count = Cache::get($this->getCacheKey(),0)) >= 40){ // Max request
    sleep(1);
}
Cache::set($this->getCacheKey(), ++$count);
// fire request

function getCacheKey(){
    return floor(time()/10); // Cool down time
}

排队似乎是更好的选择,我最终会转向排队。在将队列置于中间之前,您需要牢记一些事项。

  1. 基于回调的架构,因为您可能需要在队列中保存代码的序列化状态。基于回调的设计将把所有控制权交给 Client Class。您不必担心代码中的限制。
  2. 序列化可能很棘手,请尝试 __sleep__wakeup
  3. 您可能还想优先处理少数呼叫,您可以为此类呼叫从客户端分配配额。
  1. Jobs 包装你的 API 调用并将它们推送到单独的队列:

    ApiJob::dispatch()->onQueue('api');
    
  2. 使用 mxl/laravel-queue-rate-limit 包(我是作者)来限制 api 队列的速率。将此添加到 config/queue.php:

    'rateLimit' => [
        'api' => [
            'allows' => 40,
            'every' => 10
        ]
    ]
    
  3. 运行队列工作者:

    $ php artisan queue:work --queue api
    

另见 this answer