Google API PHP 客户端库的指数退避

Exponential Backoff With Google API PHP Client Library

我是 运行 一个网络应用程序,用于获取 Google API PHP Client Library 2.0.3 的用户列表。并将它们保存到 CSV 文件中,同时,我在屏幕上跟踪过程。我使用的代码如下:

$pageToken = null;
$optParams = array(
    "customer" => "my_customer",
    "maxResults" => 500,
    "orderBy" => "email",
    "sortOrder" => "ASCENDING"
);

try {

    $usernum = 0;

    do {

        if ($pageToken){
            $optParams['pageToken'] = $pageToken;   
        }           

        $results = $service->users->listUsers($optParams);
        $pageToken = $results->getNextPageToken();
        $users = $results->getUsers();

        foreach ($users as $user) {

            $usernum++; 

            $csvfileusers = array($user->getPrimaryEmail());
            fputcsv($savecsv, $csvfileusers);

            $usersemails = $user->getPrimaryEmail();
            print "<li>".$usernum." - <font color='#9dd7fb'>".$usersemails."</font></li>";

        }

    } while($pageToken); 

} catch (Exception $e) {

    print "An error occurred: " . $e->getMessage();

}

一切正常。问题是我不时得到 { error: { errors: [ { domain: global, reason: backendError, message: Service unavailable. Please try again } ], code: 503, message: Service unavailable. Please try again } }

我知道这意味着我向 Google 服务器发送请求的速度太快,因此我需要实施指数退避解决方案。我的问题是我不知道该怎么做。有人愿意给我提供一个示例,说明如何使用 PHP 客户端库执行此操作吗?我知道从长远来看我可能能够解决这个问题,但如果我能得到一些帮助,我将不胜感激。

很遗憾,文档是 lacking for the actual backoff implementation. However, the Google_Task_Runner class outlines the backoff implementation process. You can see how it does it here

但是,根据您的工作,您实际上并不想在执行下一次 while 迭代之前实现 exponential backoff procedure in general networking terms. You're really wanting to just throttle the request so you don't slam the API. Depending on how many $pageToken you're iterating over, you could just do a sleep

此外,$pageToken = $results->getNextPageToken();请求一次后会变成什么?因为您是从响应中设置它而不是以编程方式递减它,这可能会导致无限循环或类似性质的东西。

因此,经过 20 天的尝试和调查并感谢@kyle 提供的信息,我想出了这个指数退避解决方案。

$attemptNum = 1; // retry attempt
$expBackoff = false; // exponential backoff rety indicator

do {

    if($attemptNum <= 4) {
        try {

            $usernum = 1;

            do {

                if ($pageToken){
                    $optParams['pageToken'] = $pageToken;   
                }           

                $results = $service->users->listUsers($optParams);
                $pageToken = $results->getNextPageToken();
                $users = $results->getUsers();

                foreach ($users as $user) {

                    $csvfileusers = array($user->getPrimaryEmail());
                    fputcsv($savecsv, $csvfileusers);

                    $usersemails = $user->getPrimaryEmail();
                    print "<li>".$usernum." - <font color='#9dd7fb'>".$usersemails."</font></li>";
                    $usernum++; 

                }

            } while($pageToken); 

        } catch (Exception $e) {

            $err503ReasonA = "Service unavailable"; // Service unavailable.
            $err503ReasonB = "Backend Error"; //Backend Error

            $exception = $e->getMessage();

            if(strpos($exception, $err503Reason) !== false || strpos($exception, $err503ReasonB) !== false){    
                $expBackoff = true;
                $sleeptime = $retrynum * 1; //retrynum * seconds
                sleep($sleeptime);
                $retrynum++;
            } else {
                $expBackoff = false;
                print "There was an error -> $exception";
            }
        }

    } else {
        $expBackoff = false;
    }

} while ($expBackoff);

我已经尝试这个解决方案两天了,效果非常好。希望这可能对其他人有帮助。我现在很高兴。 :)