Handle Rate Exceeded Error
Stay organized with collections
Save and categorize content based on your preferences.
Java
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package
com.google.ads.googleads.examples.errorhandling
;
import
com.beust.jcommander.Parameter
;
import
com.google.ads.googleads.examples.utils.ArgumentNames
;
import
com.google.ads.googleads.examples.utils.CodeSampleParams
;
import
com.google.ads.googleads.lib.GoogleAdsClient
;
import
com.google.ads.googleads.v21.common.KeywordInfo
;
import
com.google.ads.googleads.v21.enums.AdGroupCriterionStatusEnum.AdGroupCriterionStatus
;
import
com.google.ads.googleads.v21.enums.KeywordMatchTypeEnum.KeywordMatchType
;
import
com.google.ads.googleads.v21.errors.GoogleAdsError
;
import
com.google.ads.googleads.v21.errors.GoogleAdsException
;
import
com.google.ads.googleads.v21.errors.QuotaErrorEnum.QuotaError
;
import
com.google.ads.googleads.v21.resources.AdGroupCriterion
;
import
com.google.ads.googleads.v21.services.AdGroupCriterionOperation
;
import
com.google.ads.googleads.v21.services.AdGroupCriterionServiceClient
;
import
com.google.ads.googleads.v21.services.MutateAdGroupCriteriaRequest
;
import
com.google.ads.googleads.v21.services.MutateAdGroupCriteriaResponse
;
import
com.google.ads.googleads.v21.utils.ResourceNames
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* Handles RateExceededError in an application. This code example runs 5 threads in parallel, each
* thread attempting to validate 100 keywords in a single request. While spanning 5 parallel threads
* is unlikely to trigger a rate exceeded error, substantially increasing the number of threads may
* have that effect. Note that this example is for illustrative purposes only, and you shouldn't
* intentionally try to trigger a rate exceed error in your application.
*/
public
class
HandleRateExceededError
{
private
static
class
HandleRateExceededErrorParams
extends
CodeSampleParams
{
@Parameter
(
names
=
ArgumentNames
.
CUSTOMER_ID
,
required
=
true
)
private
Long
customerId
;
@Parameter
(
names
=
ArgumentNames
.
AD_GROUP_ID
,
required
=
true
)
private
Long
adGroupId
;
}
public
static
void
main
(
String
[]
args
)
throws
InterruptedException
{
HandleRateExceededErrorParams
params
=
new
HandleRateExceededErrorParams
();
if
(
!
params
.
parseArguments
(
args
))
{
// Either pass the required parameters for this example on the command line, or insert them
// into the code here. See the parameter class definition above for descriptions.
params
.
customerId
=
Long
.
parseLong
(
"INSERT_CUSTOMER_ID_HERE"
);
params
.
adGroupId
=
Long
.
parseLong
(
"INSERT_AD_GROUP_ID_HERE"
);
}
GoogleAdsClient
googleAdsClient
=
null
;
try
{
googleAdsClient
=
GoogleAdsClient
.
newBuilder
().
fromPropertiesFile
().
build
();
}
catch
(
FileNotFoundException
fnfe
)
{
System
.
err
.
printf
(
"Failed to load GoogleAdsClient configuration from file. Exception: %s%n"
,
fnfe
);
System
.
exit
(
1
);
}
catch
(
IOException
ioe
)
{
System
.
err
.
printf
(
"Failed to create GoogleAdsClient. Exception: %s%n"
,
ioe
);
System
.
exit
(
1
);
}
try
{
new
HandleRateExceededError
()
.
runExample
(
googleAdsClient
,
params
.
customerId
,
params
.
adGroupId
);
}
catch
(
GoogleAdsException
gae
)
{
// GoogleAdsException is the base class for most exceptions thrown by an API request.
// Instances of this exception have a message and a GoogleAdsFailure that contains a
// collection of GoogleAdsErrors that indicate the underlying causes of the
// GoogleAdsException.
System
.
err
.
printf
(
"Request ID %s failed due to GoogleAdsException. Underlying errors:%n"
,
gae
.
getRequestId
());
int
i
=
0
;
for
(
GoogleAdsError
googleAdsError
:
gae
.
getGoogleAdsFailure
().
getErrorsList
())
{
System
.
err
.
printf
(
" Error %d: %s%n"
,
i
++
,
googleAdsError
);
}
System
.
exit
(
1
);
}
}
/**
* Runs the example.
*
* @param googleAdsClient the Google Ads API client.
* @param customerId the client customer ID.
* @param adGroupId the ID of the ad group to which keywords are added.
*/
private
void
runExample
(
GoogleAdsClient
googleAdsClient
,
long
customerId
,
long
adGroupId
)
throws
InterruptedException
{
final
int
NUM_THREADS
=
5
;
List<Thread>
threads
=
new
ArrayList
<> ();
// Adds 5 threads that validate keywords to a list.
for
(
int
i
=
0
;
i
<
NUM_THREADS
;
i
++
)
{
KeywordsThread
keywordsThread
=
new
KeywordsThread
(
googleAdsClient
,
customerId
,
adGroupId
,
i
);
Thread
thread
=
new
Thread
(
keywordsThread
);
threads
.
add
(
thread
);
}
// Starts the threads.
for
(
Thread
thread
:
threads
)
{
thread
.
start
();
}
// Ensures the calling thread waits until all threads of terminated.
for
(
Thread
thread
:
threads
)
{
thread
.
join
();
}
}
/** Thread class for validating keywords */
private
static
class
KeywordsThread
implements
Runnable
{
// Number of keywords to be validated in each API call.
private
final
int
NUM_KEYWORDS
=
100
;
// The GoogleAdsClient.
private
final
GoogleAdsClient
googleAdsClient
;
// The customer ID.
private
final
long
customerId
;
// The ad group ID to which keywords are added.
private
final
long
adGroupId
;
// Index of this thread, for identifying and debugging.
private
final
int
threadIndex
;
/**
* Initializes a new instance of the KeywordThread
*
* @param googleAdsClient the Google Ads API client.
* @param customerId the client customer ID.
* @param adGroupId the ID of the ad group to which keywords are added.
* @param threadIndex the index of the thread.
*/
public
KeywordsThread
(
GoogleAdsClient
googleAdsClient
,
long
customerId
,
long
adGroupId
,
int
threadIndex
)
{
this
.
googleAdsClient
=
googleAdsClient
;
this
.
customerId
=
customerId
;
this
.
adGroupId
=
adGroupId
;
this
.
threadIndex
=
threadIndex
;
}
/** Main method for the thread. */
public
void
run
()
{
List<AdGroupCriterionOperation>
operations
=
new
ArrayList
<> ();
for
(
int
i
=
0
;
i
<
NUM_KEYWORDS
;
i
++
)
{
// Configures the keywordText text and match type settings.
KeywordInfo
keywordInfo
=
KeywordInfo
.
newBuilder
()
.
setText
(
"mars cruise thread "
+
String
.
valueOf
(
threadIndex
)
+
" seed "
+
""
+
String
.
valueOf
(
i
))
.
setMatchType
(
KeywordMatchType
.
EXACT
)
.
build
();
String
adGroupResourceName
=
ResourceNames
.
adGroup
(
customerId
,
adGroupId
);
// Constructs an ad group criterion using the keywordText configuration above.
AdGroupCriterion
criterion
=
AdGroupCriterion
.
newBuilder
()
.
setAdGroup
(
adGroupResourceName
)
.
setStatus
(
AdGroupCriterionStatus
.
PAUSED
)
.
setKeyword
(
keywordInfo
)
.
build
();
// Creates the operation.
AdGroupCriterionOperation
operation
=
AdGroupCriterionOperation
.
newBuilder
().
setCreate
(
criterion
).
build
();
operations
.
add
(
operation
);
}
// Gets the AdGroupCriterionService. This should be done within the thread, since a service
// can only handle one outgoing HTTP request at a time.
try
(
AdGroupCriterionServiceClient
adGroupCriterionServiceClient
=
googleAdsClient
.
getLatestVersion
().
createAdGroupCriterionServiceClient
())
{
int
retryCount
=
0
;
int
retrySeconds
=
10
;
final
int
NUM_RETRIES
=
3
;
try
{
while
(
retryCount
<
NUM_RETRIES
)
{
try
{
// Creates the validateOnly request.
MutateAdGroupCriteriaRequest
mutateAdGroupCriteriaRequest
=
MutateAdGroupCriteriaRequest
.
newBuilder
()
.
setCustomerId
(
Long
.
toString
(
customerId
))
.
addAllOperations
(
operations
)
.
setValidateOnly
(
true
)
.
build
();
// Makes the mutate request. The result set will be empty because validateOnly is set
// to true in the MutateAdGroupCriteriaRequest.
MutateAdGroupCriteriaResponse
response
=
adGroupCriterionServiceClient
.
mutateAdGroupCriteria
(
mutateAdGroupCriteriaRequest
);
System
.
out
.
printf
(
"%d operations validated.%n"
,
operations
.
size
());
break
;
}
catch
(
GoogleAdsException
gae
)
{
for
(
GoogleAdsError
googleAdsError
:
gae
.
getGoogleAdsFailure
().
getErrorsList
())
{
// Checks if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
// QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
if
(
googleAdsError
.
getErrorCode
().
getQuotaError
()
==
QuotaError
.
RESOURCE_EXHAUSTED
||
googleAdsError
.
getErrorCode
().
getQuotaError
()
==
QuotaError
.
RESOURCE_TEMPORARILY_EXHAUSTED
)
{
System
.
err
.
printf
(
"Received rate exceeded error, retry after %d seconds.%n"
,
retrySeconds
);
Thread
.
sleep
(
retrySeconds
*
1000
);
retryCount
++
;
// Uses an exponential backoff policy to avoid polling too aggressively.
retrySeconds
*=
2
;
}
}
}
finally
{
if
(
retryCount
==
NUM_RETRIES
)
{
throw
new
Exception
(
String
.
format
(
"Could not recover after making %d attempts.%n"
,
retryCount
));
}
}
}
}
catch
(
Exception
e
)
{
System
.
err
.
printf
(
"Failed to validate keywords.%n"
,
e
);
System
.
exit
(
1
);
}
}
}
}
}
C#
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using
CommandLine
;
using
Google.Ads.Gax.Examples
;
using
Google.Ads.GoogleAds.Lib
;
using
Google.Ads.GoogleAds.V21.Common
;
using
Google.Ads.GoogleAds.V21.Errors
;
using
Google.Ads.GoogleAds.V21.Resources
;
using
Google.Ads.GoogleAds.V21.Services
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
static
Google
.
Ads
.
GoogleAds
.
V21
.
Enums
.
AdGroupCriterionStatusEnum
.
Types
;
using
static
Google
.
Ads
.
GoogleAds
.
V21
.
Enums
.
KeywordMatchTypeEnum
.
Types
;
using
static
Google
.
Ads
.
GoogleAds
.
V21
.
Errors
.
QuotaErrorEnum
.
Types
;
namespace
Google.Ads.GoogleAds.Examples.V21
{
/// <summary>
/// This code example demonstrates how to handle RateExceededError in an application.
/// This code example runs 5 threads in parallel, each thread attempting to validate
/// 100 keywords in a single request. While spanning 5 parallel threads is unlikely to
/// trigger a rate exceeded error, substantially increasing the number of threads may
/// have that effect. Note that this example is for illustrative purposes only, and you
/// shouldn't intentionally try to trigger a rate exceed error in your application.
/// </summary>
public
class
HandleRateExceededError
:
ExampleBase
{
/// <summary>
/// Command line options for running the <see cref="HandleRateExceededError"/> example.
/// </summary>
public
class
Options
:
OptionsBase
{
/// <summary>
/// The customer ID for which the call is made.
/// </summary>
[Option("customerId", Required = true, HelpText =
"The customer ID for which the call is made.")]
public
long
CustomerId
{
get
;
set
;
}
/// <summary>
/// ID of the ad group to which keywords are added.
/// </summary>
[Option("adGroupId", Required = true, HelpText =
"ID of the ad group to which keywords are added.")]
public
long
AdGroupId
{
get
;
set
;
}
}
/// <summary>
/// Main method, to run this code example as a standalone application.
/// </summary>
/// <param name="args">The command line arguments.</param>
public
static
void
Main
(
string
[]
args
)
{
Options
options
=
ExampleUtilities
.
ParseCommandLine<Options>
(
args
);
HandleRateExceededError
codeExample
=
new
HandleRateExceededError
();
Console
.
WriteLine
(
codeExample
.
Description
);
codeExample
.
Run
(
new
GoogleAdsClient
(),
options
.
CustomerId
,
options
.
AdGroupId
);
}
// Number of threads to use in the code example.
private
const
int
NUM_THREADS
=
5
;
// Number of keywords to be validated in each API call.
private
const
int
NUM_KEYWORDS
=
5000
;
/// <summary>
/// Returns a description about the code example.
/// </summary>
public
override
string
Description
=
>
"This code example demonstrates how to handle RateExceededError in an application. "
+
"This code example runs 5 threads in parallel, each thread attempting to validate "
+
"100 keywords in a single request. While spanning 5 parallel threads is unlikely to "
+
"trigger a rate exceeded error, substantially increasing the number of threads may "
+
"have that effect. Note that this example is for illustrative purposes only, and you "
+
"shouldn't intentionally try to trigger a rate exceed error in your application."
;
/// <summary>
/// Runs the code example.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="adGroupId">ID of the ad group to which keywords are added.</param>
public
void
Run
(
GoogleAdsClient
client
,
long
customerId
,
long
adGroupId
)
{
List<Task>
tasks
=
new
List<Task>
();
for
(
int
i
=
0
;
i
<
NUM_THREADS
;
i
++
)
{
Task
t
=
CreateKeyword
(
client
,
i
,
customerId
,
adGroupId
);
tasks
.
Add
(
t
);
}
Task
.
WaitAll
(
tasks
.
ToArray
());
}
/// <summary>
/// Displays the result from the mutate operation.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
/// <param name="adGroupId">The ad group to which keywords are added.</param>
/// <param name="threadIndex">The thread ID.</param>
private
async
Task
CreateKeyword
(
GoogleAdsClient
client
,
int
threadIndex
,
long
customerId
,
long
adGroupId
)
{
await
Task
.
Run
(()
=
>
{
// Get the AdGroupCriterionServiceClient.
AdGroupCriterionServiceClient
adGroupCriterionService
=
client
.
GetService
(
Services
.
V21
.
AdGroupCriterionService
);
List<AdGroupCriterionOperation>
operations
=
new
List<AdGroupCriterionOperation>
();
for
(
int
i
=
0
;
i
<
NUM_KEYWORDS
;
i
++
)
{
AdGroupCriterion
criterion
=
new
AdGroupCriterion
()
{
Keyword
=
new
KeywordInfo
()
{
Text
=
$"mars cruise thread {threadIndex} seed {i}"
,
MatchType
=
KeywordMatchType
.
Exact
},
AdGroup
=
ResourceNames
.
AdGroup
(
customerId
,
adGroupId
),
Status
=
AdGroupCriterionStatus
.
Paused
};
// Creates the operation.
operations
.
Add
(
new
AdGroupCriterionOperation
()
{
Create
=
criterion
});
}
int
retryCount
=
0
;
int
retrySeconds
=
30
;
const
int
NUM_RETRIES
=
3
;
while
(
retryCount
<
NUM_RETRIES
)
{
try
{
// Makes the validateOnly mutate request.
MutateAdGroupCriteriaResponse
response
=
adGroupCriterionService
.
MutateAdGroupCriteria
(
new
MutateAdGroupCriteriaRequest
()
{
CustomerId
=
customerId
.
ToString
(),
Operations
=
{
operations
},
PartialFailure
=
false
,
ValidateOnly
=
true
});
Console
.
WriteLine
(
$"[{threadIndex}] Validated {operations.Count} "
+
$"ad group criteria:"
);
break
;
}
catch
(
GoogleAdsException
e
)
{
// Checks if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
// QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
// Note: The code assumes that the developer token is approved for
// Standard Access.
if
(
e
.
Failure
!=
null
)
{
bool
isRateExceededError
=
false
;
e
.
Failure
.
Errors
.
Where
(
err
=
>
err
.
ErrorCode
.
QuotaError
==
QuotaError
.
ResourceExhausted
||
err
.
ErrorCode
.
QuotaError
==
QuotaError
.
ResourceTemporarilyExhausted
)
.
ToList
()
.
ForEach
(
delegate
(
GoogleAdsError
err
)
{
Console
.
Error
.
WriteLine
(
$"[{threadIndex}] Received rate "
+
$"exceeded error. Message says, \"{err.Message}\"."
);
isRateExceededError
=
true
;
}
);
if
(
isRateExceededError
)
{
Console
.
Error
.
WriteLine
(
$"[{threadIndex}] Will retry after {retrySeconds} seconds."
);
Thread
.
Sleep
(
retrySeconds
*
1000
);
retryCount
++
;
// Uses an exponential backoff policy to avoid polling too
// aggressively.
retrySeconds
*=
2
;
}
}
else
{
Console
.
WriteLine
(
"Failure:"
);
Console
.
WriteLine
(
$"Message: {e.Message}"
);
Console
.
WriteLine
(
$"Failure: {e.Failure}"
);
Console
.
WriteLine
(
$"Request ID: {e.RequestId}"
);
break
;
}
}
finally
{
if
(
retryCount
==
NUM_RETRIES
)
{
throw
new
Exception
(
$"[{ threadIndex }] Could not recover after "
+
$"making {retryCount} attempts."
);
}
}
}
});
}
}
}
PHP
< ?php
/**
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Ads\GoogleAds\Examples\ErrorHandling;
require __DIR__ . '/../../vendor/autoload.php';
use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V21\ResourceNames;
use Google\Ads\GoogleAds\V21\Common\KeywordInfo;
use Google\Ads\GoogleAds\V21\Enums\AdGroupCriterionStatusEnum\AdGroupCriterionStatus;
use Google\Ads\GoogleAds\V21\Enums\KeywordMatchTypeEnum\KeywordMatchType;
use Google\Ads\GoogleAds\V21\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V21\Errors\QuotaErrorEnum\QuotaError;
use Google\Ads\GoogleAds\V21\Resources\AdGroupCriterion;
use Google\Ads\GoogleAds\V21\Services\AdGroupCriterionOperation;
use Google\Ads\GoogleAds\V21\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V21\Services\MutateAdGroupCriteriaRequest;
use Google\ApiCore\ApiException;
use Exception;
/**
* Handles RateExceededError in an application. This code example runs 5 requests sequentially,
* each request attempting to validate 100 keywords. While it is unlikely that running
* these requests would trigger a rate exceeded error, substantially increasing the
* number of requests may have that effect. Note that this example is for illustrative
* purposes only, and you shouldn't intentionally try to trigger a rate exceed error in your
* application.
*/
class HandleRateExceededError
{
private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
private const AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE';
// Number of requests to be run.
private const NUM_REQUESTS = 5;
// Number of keywords to be validated in each API call.
private const NUM_KEYWORDS = 100;
// Number of retries to be run in case of a RateExceededError.
private const NUM_RETRIES = 3;
// Minimum number of seconds to wait before a retry.
private const RETRY_SECONDS = 10;
public static function main()
{
// Either pass the required parameters for this example on the command line, or insert them
// into the constants above.
$options = (new ArgumentParser())->parseCommandArguments([
ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::AD_GROUP_ID => GetOpt::REQUIRED_ARGUMENT
]);
// Generate a refreshable OAuth2 credential for authentication.
$oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();
// Construct a Google Ads client configured from a properties file and the
// OAuth2 credentials above.
$googleAdsClient = (new GoogleAdsClientBuilder())->fromFile()
->withOAuth2Credential($oAuth2Credential)
->build();
try {
self::runExample(
$googleAdsClient,
$options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
$options[ArgumentNames::AD_GROUP_ID] ?: self::AD_GROUP_ID
);
} catch (GoogleAdsException $googleAdsException) {
printf(
"Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
$googleAdsException->getRequestId(),
PHP_EOL,
PHP_EOL
);
foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
/** @var GoogleAdsError $error */
printf(
"\t%s: %s%s",
$error->getErrorCode()->getErrorCode(),
$error->getMessage(),
PHP_EOL
);
}
exit(1);
} catch (ApiException $apiException) {
printf(
"ApiException was thrown with message '%s'.%s",
$apiException->getMessage(),
PHP_EOL
);
exit(1);
}
}
/**
* Runs the example.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $adGroupId the ad group ID to validate keywords from
*/
public static function runExample(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $adGroupId
) {
// Sequentially sends the requests.
for ($i = 0; $i < self::NUM_REQUESTS; $i++) {
// Creates operations.
$operations = self::createAdGroupCriterionOperations($customerId, $adGroupId, $i);
try {
$retryCount = 0;
$retrySeconds = self::RETRY_SECONDS;
while ($retryCount < self::NUM_RETRIES) {
try {
// Sends request.
self::requestMutateAndDisplayResult(
$googleAdsClient,
$customerId,
$operations
);
break;
} catch (GoogleAdsException $googleAdsException) {
$hasRateExceededError = false;
foreach (
$googleAdsException->getGoogleAdsFailure()
->getErrors() as $googleAdsError
) {
// Checks if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
// QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
if (
$googleAdsError->getErrorCode()->getQuotaError()
== QuotaError::RESOURCE_EXHAUSTED
|| $googleAdsError->getErrorCode()->getQuotaError()
== QuotaError::RESOURCE_TEMPORARILY_EXHAUSTED
) {
printf(
'Received rate exceeded error, retry after %d seconds.%s',
$retrySeconds,
PHP_EOL
);
sleep($retrySeconds);
$hasRateExceededError = true;
$retryCount++;
// Uses an exponential back-off policy.
$retrySeconds *= 2;
break;
}
}
// Bubbles up when there is not RateExceededError
if (!$hasRateExceededError) {
throw $googleAdsException;
}
} finally {
// Bubbles up when the number of retries has already been reached.
if ($retryCount == self::NUM_RETRIES) {
throw new Exception(sprintf(
'Could not recover after making %d attempts.%s',
$retryCount,
PHP_EOL
));
}
}
}
} catch (Exception $exception) {
// Prints any unhandled exception and bubbles up.
printf(
'Failed to validate keywords.%1$s%2$s%1$s',
PHP_EOL,
$exception->getMessage()
);
throw $exception;
}
}
}
/**
* Creates ad group criterion operations.
*
* @param int $customerId the customer ID
* @param int $adGroupId the ad group ID to link the ad group criteria to
* @param int $reqIndex the request index
* @return array the created ad group criterion operations
*/
private static function createAdGroupCriterionOperations(
int $customerId,
int $adGroupId,
int $reqIndex
) {
$operations = [];
for ($i = 0; $i < self::NUM_KEYWORDS; $i++) {
// Creates a keyword info.
$keywordInfo = new KeywordInfo([
'text' => 'mars cruise req ' . $reqIndex . ' seed ' . $i,
'match_type' => KeywordMatchType::EXACT
]);
// Constructs an ad group criterion using the keyword text info above.
$adGroupCriterion = new AdGroupCriterion([
'ad_group' => ResourceNames::forAdGroup($customerId, $adGroupId),
'status' => AdGroupCriterionStatus::ENABLED,
'keyword' => $keywordInfo
]);
// Creates an ad group criterion operation.
$adGroupCriterionOperation = new AdGroupCriterionOperation();
$adGroupCriterionOperation->setCreate($adGroupCriterion);
$operations[] = $adGroupCriterionOperation;
}
return $operations;
}
/**
* Requests a mutate of ad group criterion operations and displays the results.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param array $operations the ad group criterion operations
*/
private static function requestMutateAndDisplayResult(
GoogleAdsClient $googleAdsClient,
int $customerId,
array $operations
) {
$adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient();
// Makes a validateOnly mutate request.
$response = $adGroupCriterionServiceClient->mutateAdGroupCriteria(
MutateAdGroupCriteriaRequest::build($customerId, $operations)
->setPartialFailure(false)
->setValidateOnly(true)
);
// Displays the results.
printf(
"Added %d ad group criteria:%s",
$response->getResults()->count(),
PHP_EOL
);
foreach ($response->getResults() as $result) {
/** @var GoogleAdsRow $result */
print $result->getAdGroupCriterion()->getResourceName() . PHP_EOL;
}
}
}
HandleRateExceededError::main();
Python
#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Handles RateExceededError in an application.
This code example runs 5 requests sequentially, each request attempting to
validate 100 keywords. While it is unlikely that running these requests would
trigger a rate exceeded error, substantially increasing the number of requests
may have that effect. Note that this example is for illustrative purposes only,
and you shouldn't intentionally try to trigger a rate exceed error in your
application.
"""
import
argparse
from
time
import
sleep
from
typing
import
List
,
Any
from
google.ads.googleads.client
import
GoogleAdsClient
from
google.ads.googleads.errors
import
GoogleAdsException
from
google.ads.googleads.v21.errors.types.quota_error
import
QuotaErrorEnum
from
google.ads.googleads.v21.services.services.ad_group_service
import
(
AdGroupServiceClient
,
)
from
google.ads.googleads.v21.services.services.ad_group_criterion_service
import
(
AdGroupCriterionServiceClient
,
)
from
google.ads.googleads.v21.services.types.ad_group_criterion_service
import
(
AdGroupCriterionOperation
,
MutateAdGroupCriteriaRequest
,
MutateAdGroupCriteriaResponse
,
)
# Number of requests to be run.
NUM_REQUESTS
:
int
=
5
# Number of keywords to be validated in each API call.
NUM_KEYWORDS
:
int
=
100
# Number of retries to be run in case of a RateExceededError.
NUM_RETRIES
:
int
=
3
# Minimum number of seconds to wait before a retry.
RETRY_SECONDS
:
int
=
10
def
main
(
client
:
GoogleAdsClient
,
customer_id
:
str
,
ad_group_id
:
str
)
-
> None
:
"""Runs the example code, which shows how to handle rate exceeded errors.
Args:
client: An initialized GoogleAdsClient instance.
customer_id: A valid customer account ID.
ad_group_id: The ad group ID to validate keywords from.
"""
quota_error_enum
:
QuotaErrorEnum
=
client
.
get_type
(
"QuotaErrorEnum"
)
.
QuotaError
resource_exhausted
:
QuotaErrorEnum
=
quota_error_enum
.
RESOURCE_EXHAUSTED
temp_resource_exhausted
:
QuotaErrorEnum
=
(
quota_error_enum
.
RESOURCE_TEMPORARILY_EXHAUSTED
)
for
i
in
range
(
NUM_REQUESTS
):
operations
:
List
[
AdGroupCriterionOperation
]
=
(
create_ad_group_criterion_operations
(
client
,
customer_id
,
ad_group_id
,
i
)
)
try
:
retry_count
:
int
=
0
retry_seconds
:
int
=
RETRY_SECONDS
while
retry_count
< NUM_RETRIES
:
try
:
request_mutate_and_display_result
(
client
,
customer_id
,
operations
)
break
except
GoogleAdsException
as
ex
:
has_rate_exceeded_error
:
bool
=
False
for
googleads_error
in
ex
.
failure
.
errors
:
# Checks if any of the errors are
# QuotaError.RESOURCE_EXHAUSTED or
# QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
quota_error
:
QuotaErrorEnum
=
(
googleads_error
.
error_code
.
quota_error
)
if
(
quota_error
==
resource_exhausted
or
quota_error
==
temp_resource_exhausted
):
print
(
"Received rate exceeded error, retry after"
f
"
{
retry_seconds
}
seconds."
)
sleep
(
retry_seconds
)
has_rate_exceeded_error
=
True
retry_count
+=
1
# Here exponential backoff is employed to ensure
# the account doesn't get rate limited by making
# too many requests too quickly. This increases the
# time to wait between requests by a factor of 2.
retry_seconds
*=
2
break
# Bubbles up when there is not a RateExceededError
if
not
has_rate_exceeded_error
:
raise
ex
finally
:
if
retry_count
==
NUM_RETRIES
:
raise
Exception
(
"Could not recover after making "
f
"
{
retry_count
}
attempts."
)
except
Exception
as
ex
:
# Prints any unhandled exception and bubbles up.
print
(
f
"Failed to validate keywords:
{
ex
}
"
)
raise
ex
def
create_ad_group_criterion_operations
(
client
:
GoogleAdsClient
,
customer_id
:
str
,
ad_group_id
:
str
,
request_index
:
int
,
)
-
> List
[
AdGroupCriterionOperation
]:
"""Creates ad group criterion operations.
The number of operations created depends on the number of keywords this
example should remove. That value is configurable via the NUM_KEYWORDS
variable.
Args:
client: An initialized GoogleAdsClient instance.
customer_id: A valid customer account ID.
ad_group_id: An ID for an AdGroup.
request_index: The number from a sequence of requests in which these
operations will be sent.
Returns:
A list of AdGroupCriterionOperation instances.
"""
ad_group_service
:
AdGroupServiceClient
=
client
.
get_service
(
"AdGroupService"
)
status
:
Any
=
client
.
enums
.
AdGroupCriterionStatusEnum
.
ENABLED
match_type
:
Any
=
client
.
enums
.
KeywordMatchTypeEnum
.
EXACT
operations
:
List
[
AdGroupCriterionOperation
]
=
[]
for
i
in
range
(
NUM_KEYWORDS
):
ad_group_criterion_operation
:
AdGroupCriterionOperation
=
(
client
.
get_type
(
"AdGroupCriterionOperation"
)
)
ad_group_criterion
:
AdGroupCriterion
=
(
ad_group_criterion_operation
.
create
)
ad_group_criterion
.
ad_group
=
ad_group_service
.
ad_group_path
(
customer_id
,
ad_group_id
)
ad_group_criterion
.
status
=
status
ad_group_criterion
.
keyword
.
text
=
(
f
"mars cruise req
{
request_index
}
seed
{
i
}
"
)
ad_group_criterion
.
keyword
.
match_type
=
match_type
operations
.
append
(
ad_group_criterion_operation
)
return
operations
def
request_mutate_and_display_result
(
client
:
GoogleAdsClient
,
customer_id
:
str
,
operations
:
List
[
AdGroupCriterionOperation
],
)
-
> None
:
"""Mutates a set of ad group criteria as a dry-run and displays the results.
The request is sent with validate_only set to true, so no actual mutations
will be made in the API.
Args:
client: An initialized GoogleAdsClient instance.
customer_id: A valid customer account ID.
operations: a list of AdGroupCriterionOperation instances.
"""
ad_group_criterion_service
:
AdGroupCriterionServiceClient
=
(
client
.
get_service
(
"AdGroupCriterionService"
)
)
request
:
MutateAdGroupCriteriaRequest
=
client
.
get_type
(
"MutateAdGroupCriteriaRequest"
)
request
.
customer_id
=
customer_id
request
.
operations
=
operations
request
.
validate_only
=
True
response
:
MutateAdGroupCriteriaResponse
=
(
ad_group_criterion_service
.
mutate_ad_group_criteria
(
request
=
request
)
)
print
(
f
"Added
{
len
(
response
.
results
)
}
ad group criteria:"
)
for
ad_group_criterion
in
response
.
results
:
print
(
f
"Resource name: '
{
ad_group_criterion
.
resource_name
}
'"
)
if
__name__
==
"__main__"
:
parser
:
argparse
.
ArgumentParser
=
argparse
.
ArgumentParser
(
description
=
"Handles RateExceededError in an application.."
)
# The following argument(s) should be provided to run the example.
parser
.
add_argument
(
"-c"
,
"--customer_id"
,
type
=
str
,
required
=
True
,
help
=
"The Google Ads customer ID."
,
)
parser
.
add_argument
(
"-a"
,
"--ad_group_id"
,
type
=
str
,
required
=
True
,
help
=
"The ID of an ad group belonging to the given customer."
,
)
args
=
parser
.
parse_args
()
# GoogleAdsClient will read the google-ads.yaml configuration file in the
# home directory if none is specified.
googleads_client
:
GoogleAdsClient
=
GoogleAdsClient
.
load_from_storage
(
version
=
"v21"
)
main
(
googleads_client
,
args
.
customer_id
,
args
.
ad_group_id
)
Ruby
# Encoding: utf-8
#
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Handles RateExceededError in an application. This code example runs 5 requests
# sequentially, each request attempting to validate 100 keywords. While it is
# unlikely that running these requests would trigger a rate exceeded error,
# substantially increasing the number of requests may have that effect. Note
# that this example is for illustrative purposes only, and you shouldn't
# intentionally try to trigger a rate exceed error in your application.
require
'optparse'
require
'google/ads/google_ads'
require
'date'
def
handle_rate_exceeded_error
(
customer_id
,
ad_group_id
)
# GoogleAdsClient will read a config file from
# ENV['HOME']/google_ads_config.rb when called without parameters
client
=
Google
::
Ads
::
GoogleAds
::
GoogleAdsClient
.
new
# Sequentially sends the requests.
NUM_REQUESTS
.
times
do
|
i
|
# Creates operations.
operations
=
create_ad_group_criterion_operations
(
client
,
customer_id
,
ad_group_id
,
i
)
begin
retry_count
=
0
retry_seconds
=
RETRY_SECONDS
while
retry_count
<
NUM_RETRIES
begin
# Sends request.
request_mutate_and_display_result
(
client
,
customer_id
,
operations
)
break
rescue
Google
::
Ads
::
GoogleAds
::
Errors
::
GoogleAdsError
=
>
e
has_rate_exceeded_error
=
false
e
.
failure
.
errors
.
each
do
|
error
|
# Checks if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
# QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
if
error
.
error_code
.
quota_error
==
:RESOURCE_EXHAUSTED
\
||
error
.
error_code
.
quota_error
==
:RESOURCE_TEMPORARILY_EXHAUSTED
puts
"Received rate exceeded error, retry after "
\
"
#{
retry_seconds
}
seconds."
sleep
retry_seconds
has_rate_exceeded_error
=
true
retry_count
+=
1
# Uses an exponential back-off policy.
retry_seconds
*=
2
break
end
end
# Bubbles up when there is not RateExceededError.
if
!
has_rate_exceeded_error
raise
end
ensure
# Bubbles up when the number of retries has already been reached.
if
retry_count
==
NUM_RETRIES
raise
"Could not recover after making
#{
retry_count
}
attempts."
end
end
end
rescue
StandardError
=
>
e
# Prints any unhandled exception and bubbles up.
puts
"Failed to validate keywords.
#{
e
.
message
}
"
raise
end
end
end
def
create_ad_group_criterion_operations
(
client
,
customer_id
,
ad_group_id
,
req_index
)
operations
=
[]
NUM_KEYWORDS
.
times
do
|
i
|
# Creates an ad group criterion operation.
operations
<<
client
.
operation
.
create_resource
.
ad_group_criterion
do
|
agc
|
agc
.
ad_group
=
client
.
path
.
ad_group
(
customer_id
,
ad_group_id
)
agc
.
status
=
:ENABLED
agc
.
keyword
=
client
.
resource
.
keyword_info
do
|
ki
|
ki
.
text
=
"mars cruise req
#{
req_index
}
seed
#{
i
}
"
ki
.
match_type
=
:EXACT
end
end
end
operations
end
def
request_mutate_and_display_result
(
client
,
customer_id
,
operations
)
# Makes a validate_only mutate request.
response
=
client
.
service
.
ad_group_criterion
.
mutate_ad_group_criteria
(
customer_id
:
customer_id
,
operations
:
operations
,
partial_failure
:
false
,
validate_only
:
true
,
)
# Displays the results.
puts
"Added
#{
response
.
results
.
size
}
ad group criteria:"
response
.
results
.
each
do
|
result
|
puts
"
\t
#{
result
.
resource_name
}
"
end
end
if
__FILE__
==
$PROGRAM_NAME
# Number of requests to be run.
NUM_REQUESTS
=
5
# Number of keywords to be validated in each API call.
NUM_KEYWORDS
=
100
# Number of retries to be run in case of a RateExceededError.
NUM_RETRIES
=
3
# Minimum number of seconds to wait before a retry.
RETRY_SECONDS
=
10
options
=
{}
# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
options
[
:customer_id
]
=
'INSERT_CUSTOMER_ID_HERE'
options
[
:ad_group_id
]
=
'INSERT_AD_GROUP_ID_HERE'
OptionParser
.
new
do
|
opts
|
opts
.
banner
=
sprintf
(
'Usage: ruby %s [options]'
,
File
.
basename
(
__FILE__
))
opts
.
separator
''
opts
.
separator
'Options:'
opts
.
on
(
'-C'
,
'--customer-id CUSTOMER-ID'
,
String
,
'Customer ID'
)
do
|
v
|
options
[
:customer_id
]
=
v
end
opts
.
on
(
'-A'
,
'--ad-group-id AD-GROUP-ID'
,
String
,
'Ad Group ID'
)
do
|
v
|
options
[
:ad_group_id
]
=
v
end
opts
.
separator
''
opts
.
separator
'Help:'
opts
.
on_tail
(
'-h'
,
'--help'
,
'Show this message'
)
do
puts
opts
exit
end
end
.
parse!
begin
handle_rate_exceeded_error
(
options
.
fetch
(
:customer_id
)
.
tr
(
"-"
,
""
),
options
.
fetch
(
:ad_group_id
),
)
rescue
Google
::
Ads
::
GoogleAds
::
Errors
::
GoogleAdsError
=
>
e
e
.
failure
.
errors
.
each
do
|
error
|
STDERR
.
printf
(
"Error with message: %s
\n
"
,
error
.
message
)
if
error
.
location
error
.
location
.
field_path_elements
.
each
do
|
field_path_element
|
STDERR
.
printf
(
"
\t
On field: %s
\n
"
,
field_path_element
.
field_name
)
end
end
error
.
error_code
.
to_h
.
each
do
|
k
,
v
|
next
if
v
==
:UNSPECIFIED
STDERR
.
printf
(
"
\t
Type: %s
\n\t
Code: %s
\n
"
,
k
,
v
)
end
end
raise
end
end
Perl
#!/usr/bin/perl -w
#
# Copyright 2019, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Handles RateExceededError in an application. This code example runs 5 requests
# sequentially, each request attempting to validate 100 keywords. While it is
# unlikely that running these requests would trigger a rate exceeded error,
# substantially increasing the number of requests may have that effect. Note that
# this example is for illustrative purposes only, and you shouldn't intentionally
# try to trigger a rate exceed error in your application.
use
strict
;
use
warnings
;
use
utf8
;
use
FindBin
qw($Bin)
;
use
lib
"$Bin/../../lib"
;
use
Google::Ads::GoogleAds::Client
;
use
Google::Ads::GoogleAds::Utils::GoogleAdsHelper
;
use
Google::Ads::GoogleAds::V21::Resources::AdGroupCriterion
;
use
Google::Ads::GoogleAds::V21::Common::KeywordInfo
;
use
Google::Ads::GoogleAds::V21::Enums::KeywordMatchTypeEnum
qw(EXACT)
;
use
Google::Ads::GoogleAds::V21::Enums::AdGroupCriterionStatusEnum
qw(ENABLED)
;
use
Google::Ads::GoogleAds::V21::Services::AdGroupCriterionService::AdGroupCriterionOperation
;
use
Google::Ads::GoogleAds::V21::Utils::ResourceNames
;
use
Getopt::Long
qw(:config auto_help)
;
use
Pod::Usage
;
use
Cwd
qw(abs_path)
;
use
Time::HiRes
qw(sleep)
;
# Number of requests to be run.
use
constant
NUM_REQUESTS
=
>
5
;
# Number of keywords to be validated in each API call.
use
constant
NUM_KEYWORDS
=
>
100
;
# Number of retries to be run in case of a RateExceededError.
use
constant
NUM_RETRIES
=
>
3
;
# Minimum number of seconds to wait before a retry.
use
constant
RETRY_SECONDS
=
>
10
;
# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my
$customer_id
=
"INSERT_CUSTOMER_ID_HERE"
;
my
$ad_group_id
=
"INSERT_AD_GROUP_ID_HERE"
;
sub
handle_rate_exceeded_error
{
my
(
$api_client
,
$customer_id
,
$ad_group_id
)
=
@_
;
# Sequentially send the requests.
for
(
my
$i
=
0
;
$i
<
NUM_REQUESTS
;
$i
++
)
{
# Create operations.
my
$operations
=
create_ad_group_criterion_operations
(
$customer_id
,
$ad_group_id
,
$i
);
eval
{
my
$retry_count
=
0
;
my
$retry_seconds
=
RETRY_SECONDS
;
while
(
$retry_count
<
NUM_RETRIES
)
{
# Send request.
my
$response
=
request_mutate_and_display_result
(
$api_client
,
$customer_id
,
$operations
);
if
(
$response
-
> isa
(
"Google::Ads::GoogleAds::GoogleAdsException"
))
{
my
$has_rate_exceeded_error
=
0
;
foreach
my
$error
(
@
{
$response
-
> get_google_ads_failure
()
-
> {
errors
}})
{
# Check if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
# QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
my
$quota_error
=
$error
-
> {
errorCode
}{
quotaError
};
if
(
$quota_error
&&
grep
/^$quota_error/
,
(
"RESOURCE_EXHAUSTED"
,
"RESOURCE_TEMPORARILY_EXHAUSTED"
))
{
printf
"Received rate exceeded error, retry after %d seconds.\n"
,
$retry_seconds
;
sleep
(
$retry_seconds
);
$has_rate_exceeded_error
=
1
;
$retry_count
++
;
# Use an exponential back-off policy.
$retry_seconds
*=
2
;
last
;
}
}
# Bubble up when there is not RateExceededError.
if
(
not
$has_rate_exceeded_error
)
{
die
$response
-
> get_message
();
}
}
else
{
last
;
}
# Bubble up when the number of retries has already been reached.
if
(
$retry_count
==
NUM_RETRIES
)
{
die
"Could not recover after making $retry_count attempts.\n"
,;
}
}
};
if
(
$@
)
{
# Catch and print any unhandled exception.
printf
"Failed to validate keywords.\n%s"
,
$@
;
return
0
;
}
}
return
1
;
}
# Creates ad group criterion operations.
sub
create_ad_group_criterion_operations
{
my
(
$customer_id
,
$ad_group_id
,
$request_index
)
=
@_
;
my
$operations
=
[]
;
for
(
my
$i
=
0
;
$i
<
NUM_KEYWORDS
;
$i
++
)
{
# Create a keyword info.
my
$keyword_info
=
Google::Ads::GoogleAds::V21::Common::
KeywordInfo
-
> new
({
text
=
>
"mars cruise req "
.
$request_index
.
" seed "
.
$i
,
matchType
=
>
EXACT
});
# Construct an ad group criterion using the keyword text info above.
my
$ad_group_criterion
=
Google::Ads::GoogleAds::V21::Resources::
AdGroupCriterion
-
> new
({
adGroup
=
>
Google::Ads::GoogleAds::V21::Utils::ResourceNames::
ad_group
(
$customer_id
,
$ad_group_id
),
status
=
>
ENABLED
,
keyword
=
>
$keyword_info
});
# Create an ad group criterion operation.
my
$ad_group_criterion_operation
=
Google::Ads::GoogleAds::V21::Services::AdGroupCriterionService::
AdGroupCriterionOperation
-
> new
({
create
=
>
$ad_group_criterion
});
push
@$operations
,
$ad_group_criterion_operation
;
}
return
$operations
;
}
# Requests a mutate of ad group criterion operations and displays the results.
sub
request_mutate_and_display_result
{
my
(
$api_client
,
$customer_id
,
$operations
)
=
@_
;
# Make a validateOnly mutate request.
my
$ad_group_criteria_response
=
$api_client
-
> AdGroupCriterionService
()
-
> mutate
({
customerId
=
>
$customer_id
,
operations
=
>
$operations
,
partialFailure
=
>
"false"
,
validateOnly
=
>
"true"
});
# Display the results.
if
(
not
$ad_group_criteria_response
-
> isa
(
"Google::Ads::GoogleAds::GoogleAdsException"
))
{
my
$ad_group_criterion_results
=
$ad_group_criteria_response
-
> {
results
};
printf
"Added %d ad group criteria:\n"
,
scalar
@$ad_group_criterion_results
;
foreach
my
$ad_group_criterion_result
(
@$ad_group_criterion_results
)
{
print
$ad_group_criterion_result
-
> {
resourceName
},
"\n"
;
}
}
return
$ad_group_criteria_response
;
}
# Don't run the example if the file is being included.
if
(
abs_path
(
$0
)
ne
abs_path
(
__FILE__
))
{
return
1
;
}
# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my
$api_client
=
Google::Ads::GoogleAds::
Client
-
> new
();
# By default examples are set to die on any server returned fault.
$api_client
-
> set_die_on_faults
(
0
);
# Parameters passed on the command line will override any parameters set in code.
GetOptions
(
"customer_id=s"
=
>
\
$customer_id
,
"ad_group_id=i"
=
>
\
$ad_group_id
);
# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage
(
2
)
if
not
check_params
(
$customer_id
,
$ad_group_id
);
# Call the example.
handle_rate_exceeded_error
(
$api_client
,
$customer_id
=~
s/-//g
r
,
$ad_group_id
);
=pod
=head1 NAME
handle_rate_exceeded_error
=head1 DESCRIPTION
Handles RateExceededError in an application. This code example runs 5 requests
sequentially, each request attempting to validate 100 keywords. While it is
unlikely that running these requests would trigger a rate exceeded error,
substantially increasing the number of requests may have that effect. Note that
this example is for illustrative purposes only, and you shouldn't intentionally
try to trigger a rate exceed error in your application.
=head1 SYNOPSIS
handle_rate_exceeded_error.pl [options]
-help Show the help message.
-customer_id The Google Ads customer ID.
-ad_group_id The ad group ID.
=cut
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License
, and code samples are licensed under the Apache 2.0 License
. For details, see the Google Developers Site Policies
. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-09-03 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-09-03 UTC."],[[["\u003cp\u003eThe code demonstrates how to handle \u003ccode\u003eRateExceededError\u003c/code\u003e in Google Ads API calls using multithreading and a retry mechanism with exponential backoff.\u003c/p\u003e\n"],["\u003cp\u003eIt simulates keyword validation with multiple threads to illustrate error handling in a high-request scenario.\u003c/p\u003e\n"],["\u003cp\u003eThe retry logic helps manage temporary rate limiting by pausing and retrying requests with increasing delays.\u003c/p\u003e\n"],["\u003cp\u003eThe code uses C#, PHP, Python, and Ruby, showcasing error handling across different programming languages.\u003c/p\u003e\n"],["\u003cp\u003eIt emphasizes the importance of respecting Google Ads API rate limits and implementing strategies to avoid disruptions in real-world applications.\u003c/p\u003e\n"]]],[],null,[]]