Порядок использования

Чтобы использовать пакетную обработку, выполните следующие действия:

Как создать пакетное задание

Чтобы создать ресурс BatchJob, вызовите MutateBatchJob. При создании объекта BatchJob вы можете задать для metadata.execution_limit_seconds положительное целое число, чтобы настроить приблизительную верхнюю границу (в секундах) времени выполнения задания до его автоматической отмены (см. Дополнительные рекомендации по использованию).

Java

private String createBatchJob(BatchJobServiceClient batchJobServiceClient, long customerId) {
  BatchJobOperation operation =
      BatchJobOperation.newBuilder().setCreate(BatchJob.newBuilder().build()).build();
  String batchJobResourceName =
      batchJobServiceClient
          .mutateBatchJob(Long.toString(customerId), operation)
          .getResult()
          .getResourceName();
  System.out.printf("Created a mutate job with resource name: '%s'.%n", batchJobResourceName);

  return batchJobResourceName;
}
      

C#

private static string CreateBatchJob(BatchJobServiceClient batchJobService,
    long customerId)
{
    BatchJobOperation operation = new BatchJobOperation()
    {
        Create = new BatchJob()
        {
        }
    };
    string batchJobResourceName =
        batchJobService.MutateBatchJob(customerId.ToString(), operation)
        .Result.ResourceName;
    Console.WriteLine($"Created a batch job with resource name: " +
        $"'{batchJobResourceName}'.");

    return batchJobResourceName;
}
      

PHP

private static function createBatchJob(
    BatchJobServiceClient $batchJobServiceClient,
    int $customerId
): string {
    // Creates a batch job operation to create a new batch job.
    $batchJobOperation = new BatchJobOperation();
    $batchJobOperation->setCreate(new BatchJob());

    // Issues a request to the API and get the batch job's resource name.
    $batchJobResourceName = $batchJobServiceClient->mutateBatchJob(
        MutateBatchJobRequest::build($customerId, $batchJobOperation)
    )->getResult()->getResourceName();
    printf(
        "Created a batch job with resource name: '%s'.%s",
        $batchJobResourceName,
        PHP_EOL
    );
    return $batchJobResourceName;
}
      

Python

def create_batch_job(
    batch_job_service: BatchJobServiceClient,
    customer_id: str,
    batch_job_operation: BatchJobOperation,
) -> str:
    """Creates a batch job for the specified customer ID.

    Args:
        batch_job_service: an instance of the BatchJobService message class.
        customer_id: a str of a customer ID.
        batch_job_operation: a BatchJobOperation instance set to "create"

    Returns: a str of a resource name for a batch job.
    """
    try:
        response: MutateBatchJobResponse = batch_job_service.mutate_batch_job(
            customer_id=customer_id, operation=batch_job_operation
        )
        resource_name: str = response.result.resource_name
        print(f'Created a batch job with resource name "{resource_name}"')
        return resource_name
    except GoogleAdsException as exception:
        handle_googleads_exception(exception)
        # This line will likely not be reached due to sys.exit(1) in handle_googleads_exception
        # but to satisfy the type checker, we add a return statement.
        return ""  # Or raise an exception
      

Ruby

def create_batch_job(client, batch_job_service, customer_id)
  # Creates a batch job operation to create a new batch job.
  operation = client.operation.create_resource.batch_job

  # Issues a request to the API and get the batch job's resource name.
  response = batch_job_service.mutate_batch_job(
    customer_id: customer_id,
    operation: operation
  )

  batch_job_resource_name = response.result.resource_name
  puts "Created a batch job with resource name: '#{batch_job_resource_name}'"

  batch_job_resource_name
end
      

Perl

sub create_batch_job {
  my ($batch_job_service, $customer_id) = @_;

  # Create a batch job operation.
  my $batch_job_operation =
    Google::Ads::GoogleAds::V26::Services::BatchJobService::BatchJobOperation->
    new({create => Google::Ads::GoogleAds::V26::Resources::BatchJob->new({})});

  my $batch_job_resource_name = $batch_job_service->mutate({
      customerId => $customer_id,
      operation  => $batch_job_operation
    })->{result}{resourceName};

  printf
    "Created a batch job with resource name: '%s'.\n",
    $batch_job_resource_name;

  return $batch_job_resource_name;
}
      

curl

# Creates a batch job.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.

curl -f --request POST \
"https://googleads.googleapis.com/v${API_VERSION}/customers/${CUSTOMER_ID}/batchJobs:mutate" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \
--data @- <<EOF
{
  "operation": {
    "create": {}
  }
}
EOF
      

На этом этапе свойство status задания имеет значение PENDING.

Добавьте в пакетное задание операции изменения

Добавьте один или несколько объектов MutateOperation в пакетное задание, созданное на предыдущем шаге, вызвав AddBatchJobOperations. Ответ содержит следующее:

  • total_operations – общее количество операций, добавленных в задание.
  • next_sequence_token – токен последовательности, который нужно передать в поле sequence_token при повторном вызове этого метода для добавления дополнительных операций.

В первом запросе AddBatchJobOperations для пакетного задания не должно быть параметра sequence_token. При повторном вызове AddBatchJobOperations для добавления операций укажите ранее полученный токен последовательности в поле sequence_token запроса. Если вызвать метод с пустым списком mutate_operations, возвращается ошибка BatchJobError.EMPTY_OPERATIONS. Если вызвать его с любым токеном последовательности, кроме полученного ранее, возвращается ошибка BatchJobError.INVALID_SEQUENCE_TOKEN. Если попытаться добавить операции после запуска задания, возвращается ошибка BatchJobError.CANNOT_MODIFY_JOB_AFTER_JOB_STARTS_RUNNING.

Пока status пакетного задания имеет значение PENDING, sequence_token также доступно как next_add_sequence_token в ресурсе BatchJob, который вы можете получить позже.

Если вы создаете зависимые объекты, например полную кампанию, состоящую из новой кампании и соответствующих групп объявлений, объявлений и ключевых слов, вы можете использовать временные идентификаторы, чтобы указать название ресурса.

Java

private void addAllBatchJobOperations(
    BatchJobServiceClient batchJobServiceClient, long customerId, String batchJobResourceName) {
  AddBatchJobOperationsResponse response =
      batchJobServiceClient.addBatchJobOperations(
          AddBatchJobOperationsRequest.newBuilder()
              .setResourceName(batchJobResourceName)
              .addAllMutateOperations(buildAllOperations(customerId))
              .build());
  System.out.printf(
      "%d mutate operations have been added so far.%n", response.getTotalOperations());

  // You can use this next sequence token for calling addBatchJobOperations() next time.
  System.out.printf(
      "Next sequence token for adding next operations is '%s'.%n",
      response.getNextSequenceToken());
}
      

C#

private static void AddAllBatchJobOperations(BatchJobServiceClient batchJobService,
    long customerId, string batchJobResourceName)
{
    AddBatchJobOperationsResponse response =
        batchJobService.AddBatchJobOperations(
            new AddBatchJobOperationsRequest()
            {
                ResourceName = batchJobResourceName,
                MutateOperations = { BuildAllOperations(customerId) }
            });
    Console.WriteLine($"{response.TotalOperations} mutate operations have been added" +
        $" so far.");

    // You can use this next sequence token for calling AddBatchJobOperations() next time.
    Console.WriteLine($"Next sequence token for adding next operations is " +
        $"'{response.NextSequenceToken}'.");
}
      

PHP

private static function addAllBatchJobOperations(
    BatchJobServiceClient $batchJobServiceClient,
    int $customerId,
    string $batchJobResourceName
): void {
    $response = $batchJobServiceClient->addBatchJobOperations(
        AddBatchJobOperationsRequest::build(
            $batchJobResourceName,
            '',
            self::buildAllOperations($customerId)
        )
    );
    printf(
        "%d mutate operations have been added so far.%s",
        $response->getTotalOperations(),
        PHP_EOL
    );
    // You can use this next sequence token for calling addBatchJobOperations() next time.
    printf(
        "Next sequence token for adding next operations is '%s'.%s",
        $response->getNextSequenceToken(),
        PHP_EOL
    );
}
      

Python

def add_all_batch_job_operations(
    batch_job_service: BatchJobServiceClient,
    operations: List[MutateOperation],
    resource_name: str,
) -> None:
    """Adds all mutate operations to the batch job.

    As this is the first time for this batch job, we pass null as a sequence
    token. The response will contain the next sequence token that we can use
    to upload more operations in the future.

    Args:
        batch_job_service: an instance of the BatchJobService message class.
        operations: a list of a mutate operations.
        resource_name: a str of a resource name for a batch job.
    """
    try:
        response: AddBatchJobOperationsResponse = (
            batch_job_service.add_batch_job_operations(
                resource_name=resource_name,
                sequence_token=None,  # type: ignore
                mutate_operations=operations,
            )
        )

        print(
            f"{response.total_operations} mutate operations have been "
            "added so far."
        )

        # You can use this next sequence token for calling
        # add_batch_job_operations() next time.
        print(
            "Next sequence token for adding next operations is "
            f"{response.next_sequence_token}"
        )
    except GoogleAdsException as exception:
        handle_googleads_exception(exception)
      

Ruby

def add_all_batch_job_operations(
  client,
  batch_job_service,
  customer_id,
  batch_job_resource_name)
  response = batch_job_service.add_batch_job_operations(
    resource_name: batch_job_resource_name,
    mutate_operations: build_all_operations(client, customer_id),
  )
  puts "#{response.total_operations} mutate operations have been added so far."

  # You can use this next sequence token for calling
  # add_all_batch_job_operations() next time
  puts "Next sequence token for adding next operations is " \
    "'#{response.next_sequence_token}'"
end
      

Perl

sub add_all_batch_job_operations {
  my ($batch_job_service, $customer_id, $batch_job_resource_name) = @_;

  my $add_batch_job_operations_response = $batch_job_service->add_operations({
      resourceName     => $batch_job_resource_name,
      sequenceToken    => undef,
      mutateOperations => build_all_operations($customer_id)});

  printf
    "%d batch operations have been added so far.\n",
    $add_batch_job_operations_response->{totalOperations};

  # You can use this next sequence token for calling add_operations() next time.
  printf
    "Next sequence token for adding next operations is '%s'.\n",
    $add_batch_job_operations_response->{nextSequenceToken};
}
      

curl

# Adds operations to a batch job.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.
#   BATCH_JOB_RESOURCE_NAME:
#     The resource name of the batch job to which the operations should be added
#     as returned by the previous step.

curl -f --request POST \
"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:addOperations" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \
--data @- <<EOF
{
  "mutateOperations": [
    {
      "campaignBudgetOperation": {
        "create": {
          "resourceName": "customers/${CUSTOMER_ID}/campaignBudgets/-1",
          "name": "batch job budget #${RANDOM}",
          "deliveryMethod": "STANDARD",
          "amountMicros": 5000000
        }
      }
    },
    {
      "campaignOperation": {
        "create": {
          "advertisingChannelType": "SEARCH",
          "status": "PAUSED",
          "name": "batch job campaign #${RANDOM}",
          "campaignBudget": "customers/${CUSTOMER_ID}/campaignBudgets/-1",
          "resourceName": "customers/${CUSTOMER_ID}/campaigns/-2",
          "manualCpc": {
          }
        }
      },
    }
  ]
}
EOF
      

Нажмите, чтобы посмотреть содержимое функции build operations в GitHub для вашей клиентской библиотеки:

Как запустить пакетное задание

Добавив все операции, вы можете запросить у Google Ads API запуск пакетного задания, вызвав RunBatchJob для загруженных операций. Если вызвать RunBatchJob после того, как задание уже начало выполняться, возвращается ошибка BatchJobError.CANNOT_MODIFY_JOB_AFTER_JOB_STARTS_RUNNING.

Java

private OperationFuture runBatchJob(
    BatchJobServiceClient batchJobServiceClient, String batchJobResourceName) {
  OperationFuture operationResponse =
      batchJobServiceClient.runBatchJobAsync(batchJobResourceName);

  // BEWARE! The above call returns an OperationFuture. The execution of that future depends on
  // the thread pool which is owned by batchJobServiceClient. If you use this future, you *must*
  // keep the service client in scope too.
  // See https://developers.google.com/google-ads/api/docs/client-libs/java/lro for more detail.

  System.out.printf(
      "Mutate job with resource name '%s' has been executed.%n", batchJobResourceName);

  return operationResponse;
}
      

C#

private Operation<Empty, BatchJobMetadata> RunBatchJob(
    BatchJobServiceClient batchJobService, string batchJobResourceName)
{
    Operation<Empty, BatchJobMetadata> operationResponse =
        batchJobService.RunBatchJob(batchJobResourceName);
    Console.WriteLine($"Batch job with resource name '{batchJobResourceName}' has been " +
        $"executed.");

    return operationResponse;
}
      

PHP

private static function runBatchJob(
    BatchJobServiceClient $batchJobServiceClient,
    string $batchJobResourceName
): OperationResponse {
    $operationResponse =
        $batchJobServiceClient->runBatchJob(RunBatchJobRequest::build($batchJobResourceName));
    printf(
        "Batch job with resource name '%s' has been executed.%s",
        $batchJobResourceName,
        PHP_EOL
    );
    return $operationResponse;
}
      

Python

def run_batch_job(
    batch_job_service: BatchJobServiceClient, resource_name: str
) -> Operation:
    """Runs the batch job for executing all uploaded mutate operations.

    Args:
        batch_job_service: an instance of the BatchJobService message class.
        resource_name: a str of a resource name for a batch job.

    Returns: a google.api_core.operation.Operation instance.
    """
    try:
        response: Operation = batch_job_service.run_batch_job(
            resource_name=resource_name
        )
        print(
            f'Batch job with resource name "{resource_name}" has been '
            "executed."
        )
        return response
    except GoogleAdsException as exception:
        handle_googleads_exception(exception)
        # This line will likely not be reached due to sys.exit(1) in handle_googleads_exception
        # but to satisfy the type checker, we add a return statement.
        # In a real application, you might want to return a dummy Operation or raise an error.
        return Operation(
            op_type_name="type.googleapis.com/google.protobuf.Empty",
            complete=True,
            done_callbacks=[],
            metadata_type=None,
            result_type=None,
        )  # type: ignore
      

Ruby

def run_batch_job(batch_job_service, batch_job_resource_name)
  operation_response = batch_job_service.run_batch_job(
    resource_name: batch_job_resource_name,
  )
  puts "Batch job with resource name '#{batch_job_resource_name}' " \
    "has been executed."
  operation_response
end
      

Perl

sub run_batch_job {
  my ($batch_job_service, $batch_job_resource_name) = @_;

  my $batch_job_lro =
    $batch_job_service->run({resourceName => $batch_job_resource_name});

  printf
    "Batch job with resource name '%s' has been executed.\n",
    $batch_job_resource_name;

  return $batch_job_lro;
}
      

curl

# Runs a batch job.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.
#   BATCH_JOB_RESOURCE_NAME:
#     The resource name of the batch job to run as returned by the previous step.

curl -f --request POST \
"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:run" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \
--data @- <<EOF
{}
EOF

      

Возвращаемый ответ – это длительный объект Operation, который содержит метаданные пакетного задания и информацию о его статусе.

Опрашивайте статус пакетного задания, пока оно не будет выполнено.

Опрашивайте статус пакетного задания с помощью метода Operations.GetOperation в сервисе google.longrunning.Operations (отдельно от BatchJobService), пока в поле Operation.done не появится значение true. В Google Ads API Operations.GetOperation – единственный поддерживаемый метод в google.longrunning.Operations (WaitOperation, ListOperations, CancelOperation и DeleteOperation возвращают UNIMPLEMENTED):

  • Клиентские библиотеки. Вызовите вспомогательный метод опроса или ожидания в оболочке продолжительной операции, возвращенной методом RunBatchJob (или передайте название операции методу OperationService::poll_until_done в клиентской библиотеке Perl на основе REST), который опрашивает Operations.GetOperation, пока операция не завершится (или пока не истечет заданное время ожидания опроса; в Perl перед выводом результатов убедитесь, что в возвращенном хеше done имеет значение true). В Java не закрывайте BatchJobServiceClient, пока не завершится OperationFuture.
  • REST. Отправьте HTTP-запрос GET по адресу https://googleads.googleapis.com/v26/OPERATION_NAME (где OPERATION_NAME – название ресурса Operation.name в формате customers/CUSTOMER_ID/operations/OPERATION_ID) с экспоненциальной выдержкой, пока поле Operation.done не примет значение true.

Java

private void pollBatchJob(OperationFuture operationResponse) {
  try {
    operationResponse.get(MAX_TOTAL_POLL_INTERVAL_SECONDS, TimeUnit.SECONDS);
  } catch (InterruptedException | ExecutionException | TimeoutException e) {
    System.err.printf("Failed polling the mutate job. Exception: %s%n", e);
    System.exit(1);
  }
}
      

C#

private static void PollBatchJob(Operation<Empty, BatchJobMetadata> operationResponse)
{
    PollSettings pollSettings = new PollSettings(
        Expiration.FromTimeout(TimeSpan.FromSeconds(MAX_TOTAL_POLL_INTERVAL_SECONDS)),
        TimeSpan.FromSeconds(1));
    operationResponse.PollUntilCompleted(pollSettings);
}
      

PHP

private static function pollBatchJob(OperationResponse $operationResponse): void
{
    $operationResponse->pollUntilComplete(
        [
        'initialPollDelayMillis' => self::POLL_FREQUENCY_SECONDS * 1000,
        'totalPollTimeoutMillis' => self::MAX_TOTAL_POLL_INTERVAL_SECONDS * 1000
        ]
    );
}
      

Python

def poll_batch_job(
    operations_response: Operation, event: asyncio.Event
) -> None:
    """Polls the server until the batch job execution finishes.

    Sets the initial poll delay time and the total time to wait before time-out.

    Args:
        operations_response: a google.api_core.operation.Operation instance.
        event: an instance of asyncio.Event to invoke once the operations have
            completed, alerting the awaiting calling code that it can proceed.
    """
    loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()

    def done_callback(future: Coroutine[Any, Any, Any]) -> None:
        # The operations_response object will call callbacks from a daemon
        # thread so we must use a threadsafe method of setting the event here
        # otherwise it will not trigger the awaiting code.
        loop.call_soon_threadsafe(event.set)

    # operations_response represents a Long-Running Operation or LRO. The class
    # provides an interface for polling the API to check when the operation is
    # complete. Below we use the asynchronous interface, but there's also a
    # synchronous interface that uses the Operation.result method.
    # See: https://googleapis.dev/python/google-api-core/latest/operation.html
    operations_response.add_done_callback(done_callback)  # type: ignore
      

Ruby

def poll_batch_job(operation_response)
  operation_response.wait_until_done!
end
      

Perl

sub poll_batch_job {
  my ($operation_service, $batch_job_lro) = @_;

  $operation_service->poll_until_done({
    name                 => $batch_job_lro->{name},
    pollFrequencySeconds => POLL_FREQUENCY_SECONDS,
    pollTimeoutSeconds   => POLL_TIMEOUT_SECONDS
  });
}
      

curl

# Gets the status of a batch job.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.
#   BATCH_JOB_OPERATION_NAME:
#     The operation name of the running batch job as returned by the previous
#     step.

curl -f --request GET \
"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_OPERATION_NAME}" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \

      

Вы также можете запросить ресурс batch_job с помощью метода GoogleAdsService.Search или GoogleAdsService.SearchStream, выбрав batch_job.status и определенные подполя BatchJobMetadata (например, batch_job.metadata.estimated_completion_ratio и batch_job.metadata.executed_operation_count), пока batch_job.status не станет DONE. Каждый запрос Operations.GetOperation или GAQL без разбивки на страницы считается одной операцией в рамках дневной квоты API. Если вы отслеживаете несколько параллельных пакетных заданий, один запрос GAQL (WHERE batch_job.id IN (...) или WHERE batch_job.status = 'RUNNING') проверяет их все, а не опрашивает каждую продолжительную операцию по отдельности.

Если для параметра Operation.done задано значение true, продолжительная операция возвращает пустой ответ без ошибок. Чтобы проверить результаты отдельных операций, вызовите ListBatchJobResults.

Как получить существующую продолжительную операцию

Если ваше приложение опрашивает пакетные задания из отдельного процесса или должно возобновить опрос после перезапуска, вы можете получить название продолжительной операции с помощью GoogleAdsService.Search или GoogleAdsService.SearchStream.

  1. Запросите ресурс batch_job, чтобы прочитать его поле long_running_operation:

    SELECT
      batch_job.id,
      batch_job.status,
      batch_job.long_running_operation
    FROM batch_job
    WHERE batch_job.id = BATCH_JOB_ID
    

    Замените BATCH_JOB_ID числовым идентификатором пакетного задания.

  2. Убедитесь, что поле batch_job.status имеет значение RUNNING или DONE (поле long_running_operation не задано, пока задание имеет статус PENDING, поскольку продолжительная операция не существует, пока не вызван метод RunBatchJob), и прочитайте строку long_running_operation из возвращенного объекта BatchJob.

  3. Проверьте операцию, используя строку с ее названием:

    • Клиентские библиотеки. Получите клиент операций из клиента BatchJobService (getOperationsClient() в Java и PHP, RunBatchJobOperationsClient в C#, transport.operations_client в Python, operations_client в Ruby или $api_client->OperationService() в Perl), чтобы аутентификация Google Рекламы и заголовки login-customer-id настраивались автоматически, а не создавали экземпляр отдельного OperationsClient. Вызовите Operations.GetOperation (или OperationService::get в Perl) для однократной проверки статуса или используйте название операции, чтобы возобновить оболочку продолжительной операции и выполнять опрос до завершения (runBatchJobOperationCallable().resumeFutureCall в Java, PollOnceRunBatchJob в C#, resumeOperation в PHP, google.api_core.operation.from_gapic в Operation, возвращенном get_operation в Python, wait_until_done! в Gapic::Operation, возвращенном get_operation в Ruby, или name в OperationService::poll_until_done в Perl).
    • REST. Отправьте HTTP-запрос GET по адресу https://googleads.googleapis.com/v26/OPERATION_NAME.

    Поскольку OPERATION_NAME кодирует основную версию API, в которой был создан BatchJob, Operations.GetOperation (даже через активную конечную точку REST v26) завершается ошибкой RequestError.UNSUPPORTED_VERSION, если эта версия была прекращена. Вместо этого отправляйте запросы к batch_job.status напрямую с помощью GoogleAdsService.

Что такое метаданные операции

При опросе продолжительной операции или запросе ресурса batch_job BatchJobMetadata предоставляет сведения о ходе выполнения пакетного задания:

  • creation_date_time – временная метка создания пакетного задания.
  • start_date_time – временная метка, указывающая, когда началось выполнение пакетного задания (заполняется при запросе batch_job.metadata.start_date_time с GoogleAdsService; опускается из Operation.metadata в RunBatchJob и Operations.GetOperation).
  • completion_date_time – временная метка завершения пакетного задания (указывается, только если задание выполнено).
  • estimated_completion_ratio – приблизительная доля выполненной работы (от 0,0 до 1,0).
  • operation_count – общее количество операций в пакетном задании.
  • executed_operation_count – количество операций, выполненных к настоящему моменту.
  • execution_limit_seconds – приблизительное верхнее ограничение в секундах на время выполнения пакетного задания до его отмены. Заполняется при запросе batch_job.metadata.execution_limit_seconds с GoogleAdsService, если при создании задания было задано положительное ограничение. Опускается из Operation.metadata в RunBatchJob и Operations.GetOperation.

Эти поля, особенно estimated_completion_ratio и количество операций, помогут вам оценить ход выполнения задания, рассчитать оставшееся время и скорректировать частоту опросов. Например, вы можете отправлять запросы реже, если значение estimated_completion_ratio низкое, и чаще, если оно приближается к 1,0.

Как получить список всех результатов пакетного задания

Когда пакетное задание будет выполнено, вызовите ListBatchJobResults, чтобы получить статус и ответ для каждой операции в задании:

Java

private void fetchAndPrintResults(
    BatchJobServiceClient batchJobServiceClient, String batchJobResourceName) {
  System.out.printf(
      "Mutate job with resource name '%s' has finished. Now, printing its results...%n",
      batchJobResourceName);
  // Gets all the results from running mutate job and prints their information.
  ListBatchJobResultsPagedResponse batchJobResults =
      batchJobServiceClient.listBatchJobResults(
          ListBatchJobResultsRequest.newBuilder()
              .setResourceName(batchJobResourceName)
              .setPageSize(PAGE_SIZE)
              .build());
  for (BatchJobResult batchJobResult : batchJobResults.iterateAll()) {
    System.out.printf(
        "Mutate job #%d has a status '%s' and response of type '%s'.%n",
        batchJobResult.getOperationIndex(),
        batchJobResult.getStatus().getMessage().isEmpty()
            ? "N/A"
            : batchJobResult.getStatus().getMessage(),
        batchJobResult
                .getMutateOperationResponse()
                .getResponseCase()
                .equals(ResponseCase.RESPONSE_NOT_SET)
            ? "N/A"
            : batchJobResult.getMutateOperationResponse().getResponseCase());
  }
}
      

C#

private static void FetchAndPrintResults(BatchJobServiceClient batchJobService,
    string batchJobResourceName)
{
    Console.WriteLine($"batch job with resource name '{batchJobResourceName}' has " +
        $"finished. Now, printing its results...");

    ListBatchJobResultsRequest request = new ListBatchJobResultsRequest()
    {
        ResourceName = batchJobResourceName,
        PageSize = PAGE_SIZE,
    };
    ListBatchJobResultsResponse resp = new ListBatchJobResultsResponse();
    // Gets all the results from running batch job and prints their information.
    foreach (BatchJobResult batchJobResult in
        batchJobService.ListBatchJobResults(request))
    {
        if (!batchJobResult.IsFailed)
        {
            Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} is " +
                $"successful and response is of type " +
                $"'{batchJobResult.MutateOperationResponse.ResponseCase}'.");
        }
        else
        {
            Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} " +
                $"failed with error message {batchJobResult.Status.Message}.");

            foreach (GoogleAdsError error in batchJobResult.Failure.Errors)
            {
                Console.WriteLine($"Error found: {error}.");
            }
        }
    }
}
      

PHP

    private static function fetchAndPrintResults(
        BatchJobServiceClient $batchJobServiceClient,
        string $batchJobResourceName
    ): void {
        printf(
            "Batch job with resource name '%s' has finished. Now, printing its results...%s",
            $batchJobResourceName,
            PHP_EOL
        );
        // Gets all the results from running batch job and print their information.
        $batchJobResults = $batchJobServiceClient->listBatchJobResults(
            ListBatchJobResultsRequest::build($batchJobResourceName)->setPageSize(self::PAGE_SIZE)
        );
        foreach ($batchJobResults->iterateAllElements() as $batchJobResult) {
            /**
 * @var BatchJobResult $batchJobResult
*/
            printf(
                "Batch job #%d has a status '%s' and response of type '%s'.%s",
                $batchJobResult->getOperationIndex(),
                $batchJobResult->getStatus()
                    ? $batchJobResult->getStatus()->getMessage() : 'N/A',
                $batchJobResult->getMutateOperationResponse()
                    ? $batchJobResult->getMutateOperationResponse()->getResponse()
                    : 'N/A',
                PHP_EOL
            );
        }
    }
      

Python

def fetch_and_print_results(
    client: GoogleAdsClient,
    batch_job_service: BatchJobServiceClient,
    resource_name: str,
) -> None:
    """Prints all the results from running the batch job.

    Args:
        client: an initialized GoogleAdsClient instance.
        batch_job_service: an instance of the BatchJobService message class.
        resource_name: a str of a resource name for a batch job.
    """
    print(
        f'Batch job with resource name "{resource_name}" has finished. '
        "Now, printing its results..."
    )

    list_results_request: ListBatchJobResultsRequest = client.get_type(
        "ListBatchJobResultsRequest"
    )
    list_results_request.resource_name = resource_name
    list_results_request.page_size = 1000
    # Gets all the results from running batch job and prints their information.
    batch_job_results: ListBatchJobResultsResponse = (
        batch_job_service.list_batch_job_results(request=list_results_request)
    )

    for batch_job_result in batch_job_results:
        status: str = batch_job_result.status.message
        status = status if status else "N/A"
        result: Any = batch_job_result.mutate_operation_response
        result = result or "N/A"
        print(
            f"Batch job #{batch_job_result.operation_index} "
            f'has a status "{status}" and response type "{result}"'
        )
      

Ruby

def fetch_and_print_results(batch_job_service, batch_job_resource_name)
  puts "Batch job with resource name '#{batch_job_resource_name}' has " \
    "finished. Now, printing its results..." \

  # Gets all the results from running batch job and print their information.
  batch_job_results = batch_job_service.list_batch_job_results(
    resource_name: batch_job_resource_name,
    page_size: PAGE_SIZE,
  )
  batch_job_results.each do |result|
    puts "Batch job ##{result.operation_index} has a status " \
      "#{result.status ? result.status.message : 'N/A'} and response of type " \
      "#{result.mutate_operation_response ? result.mutate_operation_response.response : 'N/A'}"
  end
end
      

Perl

sub fetch_and_print_results {
  my ($batch_job_service, $batch_job_resource_name) = @_;

  printf "Batch job with resource name '%s' has finished. " .
    "Now, printing its results...\n", $batch_job_resource_name;

  # Get all the results from running batch job and print their information.
  my $list_batch_job_results_response = $batch_job_service->list_results({
    resourceName => $batch_job_resource_name,
    pageSize     => PAGE_SIZE
  });

  foreach my $batch_job_result (@{$list_batch_job_results_response->{results}})
  {
    printf
      "Batch job #%d has a status '%s' and response of type '%s'.\n",
      $batch_job_result->{operationIndex},
      $batch_job_result->{status} ? $batch_job_result->{status}{message}
      : "N/A",
      $batch_job_result->{mutateOperationResponse}
      ? [keys %{$batch_job_result->{mutateOperationResponse}}]->[0]
      : "N/A";
  }
}
      

curl

# Gets the results of a batch job.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.
#   BATCH_JOB_RESOURCE_NAME:
#     The operation name of the running batch job as returned by the previous
#     step.
curl -f --request GET \
"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:listResults?pageSize=1000" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}"

      

В ListBatchJobResultsRequest поле page_size по умолчанию принимает максимальное значение 1000, если оно не указано или задано как 0. Если задать для параметра page_size значение больше 1000 или меньше 0, возвращается ошибка BatchJobError.INVALID_PAGE_SIZE.

Каждый объект BatchJobResult идентифицирует соответствующую операцию с помощью operation_index – индекса загруженного объекта MutateOperation в пакетном задании, начинающегося с нуля.

  • Успешная операция. Заполняется поле mutate_operation_response (его поле response содержит resource_name измененного ресурса, а также все изменяемые поля, если для response_content_type задано значение MUTABLE_RESOURCE), а поле status не заполнено.
  • Неудачная (или невыполненная) операция: mutate_operation_response не задано, а status содержит сведения об ошибке для операции.

Как отменить или удалить пакетное задание

Способ остановки или отмены пакетного задания зависит от того, был ли вызван метод RunBatchJob:

Обработка ошибок

BatchJobService выполняет стандартные операции с включенной частичной ошибкой (успешные операции фиксируются, даже если другие операции в том же задании завершаются ошибкой, за исключением атомарных подпакетов) и автоматически повторяет операции, которые завершаются ошибкой из-за временных ошибок. Однако не все сценарии сбоев можно избежать. Операции, которые не удалось выполнить из-за ошибок проверки, можно исправить и повторно отправить в новом пакетном задании. Аналогично, если пакетное задание отменено или прервано до завершения всех операций, вы можете повторно отправить невыполненные операции (operation_index >= executed_operation_count) вместе со всеми неудачными операциями из выполненного префикса в новом пакетном задании.