【问题标题】:Using sleep() to avoid hitting rate limit not working使用 sleep() 来避免达到速率限制不起作用
【发布时间】:2017-12-28 21:48:27
【问题描述】:

我正在使用的 API 达到了我的速率限制,我很困惑,因为我用来防止这种情况的方法似乎应该可以正常工作,但它并不是 100% 的时间都有效。我在每个 API 调用之前都有这一行,它应该调用一个函数来检查我是否接近我的极限,如果我接近了,那么睡眠时间足够长以重置我的命中计数。像这样:

if (isset($http_response_header)) {rateLimit($http_response_header);} 
file_get_contents($endpointURL);

函数如下:

function rateLimit($header)
{
// get hit count from $header

// $count[0] is how many hits per second
// I have a limit of 20 per second

// $count[1] is how many hits per 2 minutes
// I have a limit of 100 per 2 minutes

if ($count[0] == 19) {sleep(1); return;}
if ($count[1] == 99) {sleep(120); return;}
}

如果我每秒发出的最大呼叫数,它应该休眠 1 秒,如果我每 2 分钟发出的最大呼叫数,它应该休眠两分钟。我的代码有问题吗,还是 API 错误地限制了我?

这是整个rateLimit 函数,因为有人想知道我是如何解析它的:

function rateLimit($header)
{
$pos1 = strpos($header[7], ' ') + 1;
$pos2 = strpos($header[7], ':', $pos1);
$count[0] = substr($header[7], $pos1, ($pos2 - $pos1));

$pos1 = strpos($header[7], ',') + 1;
$pos2 = strpos($header[7], ':', $pos1);
$count[1] = substr($header[7], $pos1, ($pos2 - $pos1));

if ($count[0] == 18) {sleep(1); return;}
if ($count[1] == 98) {sleep(120); return;}
}

【问题讨论】:

  • RTM: http_response_header 不返回整数数组,请说明您的解析方式。睡觉也不是一个好主意,而只是返回 false 并使用 rateLimit 函数作为条件检查。
  • 您是否需要经常访问 api?高达 20 hits/s 听起来很刺耳。它只是向我尖叫“缓存”,但你可能有一些实时更新的东西正在发生..?
  • @Lawrence Cherone 我用整个函数更新了我的问题,显示了我是如何解析它的。我正在使用 sleep 来推迟 API 调用而不是跳过它,因为无论需要多长时间,我都需要每次调用都能正常工作。为什么我在你的名字前输入@ 不起作用?我正在使用 Riot Games (League of Legends) API 的开发密钥,该密钥受到严格限制,因为它仅用于测试目的。他们在一周左右的时间里不接受更好的钥匙申请,但我正在使用我在那之前拥有的东西。
  • @MelerLawler 如果您使用的是开发密钥并且仅将其用于开发,那么只需缓存响应并使用您的本地副本。无需一次又一次地为同一个文档点击 api

标签: php api limit endpoint rate


【解决方案1】:

您没有在 rateLimit 函数中将 $count 定义为数组,因此您可能会收到未定义索引警告,这会破坏您的代码。

所以要么这样做

function rateLimit($header)
{
    $count = [];    

    $pos1 = strpos($header[7], ' ') + 1;
    $pos2 = strpos($header[7], ':', $pos1);
    $count[0] = substr($header[7], $pos1, ($pos2 - $pos1));

    $pos1 = strpos($header[7], ',') + 1;
    $pos2 = strpos($header[7], ':', $pos1);
    $count[1] = substr($header[7], $pos1, ($pos2 - $pos1));

    if ($count[0] == 18) {sleep(1); return;}
    if ($count[1] == 98) {sleep(120); return;}
}

或者这个

function rateLimit($header)
{
    $pos1 = strpos($header[7], ' ') + 1;
    $pos2 = strpos($header[7], ':', $pos1);

    $pos1 = strpos($header[7], ',') + 1;
    $pos2 = strpos($header[7], ':', $pos1);

    if (substr($header[7], $pos1, ($pos2 - $pos1)) == 18) {sleep(1); return;}
    if (substr($header[7], $pos1, ($pos2 - $pos1)) == 98) {sleep(120); return;}
}

【讨论】:

  • 不幸的是,这些解决方案都不起作用(我可以确认问题不是未能声明数组,因为使用测试标头它工作正常)。看来我的 rateLimit 函数必须工作,因为逻辑很简单,我测试了 $header[7] 值的不同可能性,并且它们都被正确解析。 $header[7] 看起来像这样:X-App-Rate-Limit-Count: x:1,y:120 其中 x 和 y 分别是我每秒和每 2 分钟的命中数。也许 API 错误地限制了我。
  • 不,事实证明 API 仅在我达到限制时才限制我。不知道为什么我的代码在此之前没有让我 sleep
  • 我发现如果$count[1] == 99 删除线if ($count[0] == 19) {sleep(1); return;} 会使它休眠。会弄清楚为什么会这样并报告回来。
  • 我想我明白了。我认为这两个计数在同一个 API 调用上都达到了最大值,但是 rateLimit 函数在休眠一秒钟后返回,以重置第一个计数,但这忽略了第二个计数也需要重置。跨度>
【解决方案2】:

问题原来是我总是在键 7 中查找告诉我命中计数的字符串,但有时它位于不同的键中。

【讨论】:

    猜你喜欢
    • 2016-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-23
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    相关资源
    最近更新 更多