public static function mutateEntities($adwords_user, $service_name, $ops){
$service = $adwords_user->GetService($service_name, Utils::ADWORDS_VERSION);
$opc = count($ops);
if ($opc > 5000)
throw new \Exception('Too many operations for ' . $service_name);
for ($iii = 0; $iii < 5; $iii++){
RateLimiter::throttle($adwords_user->getClientCustomerId(), $opc);
try {
$service->mutate($ops);
break;
} catch (\Exception $e){
$errors = ( ($e instanceof \SoapFault) ? \ErrorUtils::GetApiErrors($e) : null);
if (!Utils::isRetriable($errors))
throw new NonRetriableException('Non-retriable error: ' . $e->getMessage()); // here I just check if the error seems to be due to a bad request and if so, do not retry
RateLimiter::reportError($adwords_user->getClientCustomerId(), $iii, $errors);
}
if ($iii + 1 == 5){
throw new \Exception('Adwords query failed after max retries. ' . $e->getMessage());
}
}
}
public static function reportError($account, $attemptNum, $errors = null){
if (!$account)
$account = self::NO_ACCOUNT;
// determine if it is a rate limit issue
$error_types = [];
$rateScope = $rateName = null;
if ($errors)
foreach ($errors as $i){
@$error_types[ $i->ApiErrorType ]++;
if ($i->ApiErrorType == 'RateExceededError')
list($rateScope, $rateName) = array($i->rateScope, $i->rateName);
}
error_log('AdwordsRateLimiter error ' . $account . ' ' . $rateScope . ' ' . $rateName . ' ' . ($rateScope ? 'RATE LIMIT EXCEEDED' : '') . '; ' . json_encode($error_types) );
if ($rateScope && $rateName){
$data = array('account' => $account, 'err' => '1', 'attemptNum' => $attemptNum, 'rateScope' => $rateScope, 'rateName' => $rateName);
} else {
$data = array('account' => $account, 'err' => '1', 'attemptNum' => $attemptNum);
}
// log $data: self::sendRequest($data);
}