Ява
// 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.v17.common.KeywordInfo;
import com.google.ads.googleads.v17.enums.AdGroupCriterionStatusEnum.AdGroupCriterionStatus;
import com.google.ads.googleads.v17.enums.KeywordMatchTypeEnum.KeywordMatchType;
import com.google.ads.googleads.v17.errors.GoogleAdsError;
import com.google.ads.googleads.v17.errors.GoogleAdsException;
import com.google.ads.googleads.v17.errors.QuotaErrorEnum.QuotaError;
import com.google.ads.googleads.v17.resources.AdGroupCriterion;
import com.google.ads.googleads.v17.services.AdGroupCriterionOperation;
import com.google.ads.googleads.v17.services.AdGroupCriterionServiceClient;
import com.google.ads.googleads.v17.services.MutateAdGroupCriteriaRequest;
import com.google.ads.googleads.v17.services.MutateAdGroupCriteriaResponse;
import com.google.ads.googleads.v17.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);
}
}
}
}
}
С#
// 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.V17.Common;
using Google.Ads.GoogleAds.V17.Errors;
using Google.Ads.GoogleAds.V17.Resources;
using Google.Ads.GoogleAds.V17.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static Google.Ads.GoogleAds.V17.Enums.AdGroupCriterionStatusEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.KeywordMatchTypeEnum.Types;
using static Google.Ads.GoogleAds.V17.Errors.QuotaErrorEnum.Types;
namespace Google.Ads.GoogleAds.Examples.V17
{
/// <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.V17.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\V17\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V17\ResourceNames;
use Google\Ads\GoogleAds\V17\Common\KeywordInfo;
use Google\Ads\GoogleAds\V17\Enums\AdGroupCriterionStatusEnum\AdGroupCriterionStatus;
use Google\Ads\GoogleAds\V17\Enums\KeywordMatchTypeEnum\KeywordMatchType;
use Google\Ads\GoogleAds\V17\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V17\Errors\QuotaErrorEnum\QuotaError;
use Google\Ads\GoogleAds\V17\Resources\AdGroupCriterion;
use Google\Ads\GoogleAds\V17\Services\AdGroupCriterionOperation;
use Google\Ads\GoogleAds\V17\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V17\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();
Питон
#!/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 google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
# 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
def main(client, customer_id, ad_group_id):
"""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 = client.get_type("QuotaErrorEnum").QuotaError
resource_exhausted = quota_error_enum.RESOURCE_EXHAUSTED
temp_resource_exhausted = quota_error_enum.RESOURCE_TEMPORARILY_EXHAUSTED
for i in range(NUM_REQUESTS):
operations = create_ad_group_criterion_operations(
client, customer_id, ad_group_id, i
)
try:
retry_count = 0
retry_seconds = 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 = 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 = 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, customer_id, ad_group_id, request_index
):
"""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 = client.get_service("AdGroupService")
status = client.enums.AdGroupCriterionStatusEnum.ENABLED
match_type = client.enums.KeywordMatchTypeEnum.EXACT
operations = []
for i in range(NUM_KEYWORDS):
ad_group_criterion_operation = client.get_type(
"AdGroupCriterionOperation"
)
ad_group_criterion = 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, customer_id, operations):
"""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 = client.get_service("AdGroupCriterionService")
request = client.get_type("MutateAdGroupCriteriaRequest")
request.customer_id = customer_id
request.operations = operations
request.validate_only = True
response = 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(
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.load_from_storage(version="v17")
main(googleads_client, args.customer_id, args.ad_group_id)
Руби
# 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("\tOn 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("\tType: %s\n\tCode: %s\n", k, v)
end
end
raise
end
end
Перл
#!/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::V17::Resources::AdGroupCriterion;
use Google::Ads::GoogleAds::V17::Common::KeywordInfo;
use Google::Ads::GoogleAds::V17::Enums::KeywordMatchTypeEnum qw(EXACT);
use Google::Ads::GoogleAds::V17::Enums::AdGroupCriterionStatusEnum qw(ENABLED);
use
Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation;
use Google::Ads::GoogleAds::V17::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::V17::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::V17::Resources::AdGroupCriterion->new({
adGroup => Google::Ads::GoogleAds::V17::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::V17::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/-//gr, $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