Page Summary
-
Batch processing involves creating a batch job, adding operations, running the job, and then polling its status and listing the results.
-
To create a batch job resource, call
MutateBatchJob, which initially sets the job's status toPENDING. -
Add operations to the batch job by calling
AddBatchJobOperationsand use the returned sequence token for subsequent calls to add more operations. -
After adding all operations, request the Google Ads API to execute the batch job by calling
RunBatchJob, which returns a long-runningOperation. -
Poll the status of the batch job using the LRO's
GetOperationuntil itsdonevalue istrue, then useListBatchJobResultsto retrieve and examine the outcome of each operation.
The steps for using batch processing are as follows:
Create a new batch job
To create a BatchJob resource, call
MutateBatchJob. When you construct the
BatchJob object, you can optionally set
metadata.execution_limit_seconds to a positive integer to
configure an approximate upper bound, in seconds, on how long the job can run
before being automatically canceled (see
Additional usage guidance).
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
At this point in the process, the status of the job is
PENDING.
Add mutate operations to the batch job
Add one or more MutateOperation objects to the batch job
created in the previous step by calling
AddBatchJobOperations. The
response then contains the following:
total_operations: Total number of operations added so far for this job.next_sequence_token: Sequence token to pass in thesequence_tokenfield when you call this method again to add more operations.
The first AddBatchJobOperations request for a
batch job must omit sequence_token. When you call
AddBatchJobOperations again to add more
operations, specify the previously obtained sequence token in the
sequence_token field of the
request. Calling the method with an empty
mutate_operations list returns a
BatchJobError.EMPTY_OPERATIONS error, calling it with any
sequence token other than the previously obtained one returns a
BatchJobError.INVALID_SEQUENCE_TOKEN error, and
attempting to add operations after the job starts running returns a
BatchJobError.CANNOT_MODIFY_JOB_AFTER_JOB_STARTS_RUNNING
error.
While the batch job's status is
PENDING, sequence_token is also available as
next_add_sequence_token on the
BatchJob resource, which you can retrieve
later.
If you're creating dependent objects such as a complete campaign consisting of a new campaign and corresponding ad groups, ads, and keywords, you can use temporary IDs to specify a resource name.
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
Click to see the content of the build operations function in GitHub for your client library:
Java
buildAllOperations()
C#
BuildAllOperations()
PHP
buildAllOperations()
Python
build_all_operations()
Ruby
build_all_operations()
Perl
build_all_operations
Run the batch job
After you add all your operations, you can request the Google Ads API to run the batch
job by calling RunBatchJob on the uploaded operations.
Calling RunBatchJob after the job has already started running
returns a
BatchJobError.CANNOT_MODIFY_JOB_AFTER_JOB_STARTS_RUNNING
error.
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
The returned response is a long-running Operation object that
contains the metadata of your batch job and information about the job status.
Poll the status of the batch job until it's done
Poll the batch job status with the
Operations.GetOperation method on the
google.longrunning.Operations service (separate from
BatchJobService) until the
Operation.done field is true. In the Google Ads API,
Operations.GetOperation is the only supported method on
google.longrunning.Operations (WaitOperation,
ListOperations, CancelOperation, and DeleteOperation return
UNIMPLEMENTED):
- Client libraries: Call the polling or wait helper on the long-running
operation wrapper returned by
RunBatchJob(or pass the operation name toOperationService::poll_until_donein the REST-based Perl client library), which pollsOperations.GetOperationuntil the operation completes (or until the configured poll timeout expires; in Perl, verify thatdoneistrueon the returned hash before listing results). In Java, keepBatchJobServiceClientopen untilOperationFuturefinishes. - REST: Send an HTTP
GETrequest tohttps://googleads.googleapis.com/v26/OPERATION_NAME(whereOPERATION_NAMEis theOperation.nameresource name, formatted ascustomers/CUSTOMER_ID/operations/OPERATION_ID) with exponential backoff until theOperation.donefield istrue.
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}" \
Alternatively, query the batch_job resource with the
GoogleAdsService.Search or
GoogleAdsService.SearchStream method, selecting
batch_job.status and specific
BatchJobMetadata subfields (such as
batch_job.metadata.estimated_completion_ratio and
batch_job.metadata.executed_operation_count) until
batch_job.status is DONE. Each
Operations.GetOperation or non-paginated GAQL request
counts as one operation toward your daily API quota; when you monitor
multiple concurrent batch jobs, a single GAQL query (WHERE batch_job.id IN
(...) or WHERE batch_job.status = 'RUNNING') checks all of them in one
request instead of polling each long-running operation individually.
When Operation.done is true, the long-running
operation returns an empty response without per-operation errors—call
ListBatchJobResults to inspect individual operation
outcomes.
Retrieve an existing long-running operation
If your application polls batch jobs from a separate process or needs to resume
polling after a restart, you can retrieve the long-running operation name using
GoogleAdsService.Search or
GoogleAdsService.SearchStream:
Query the
batch_jobresource to read itslong_running_operationfield:SELECT batch_job.id, batch_job.status, batch_job.long_running_operation FROM batch_job WHERE batch_job.id = BATCH_JOB_IDReplace
BATCH_JOB_IDwith the numeric ID of the batch job.Verify that
batch_job.statusisRUNNINGorDONE(long_running_operationis unset while the job isPENDINGbecause no long-running operation exists untilRunBatchJobis called), and read thelong_running_operationstring from the returnedBatchJobobject.Poll or inspect the operation by using that operation name string:
- Client libraries: Obtain the operations client from your
BatchJobServiceclient (getOperationsClient()in Java and PHP,RunBatchJobOperationsClientin C#,transport.operations_clientin Python,operations_clientin Ruby, or$api_client->OperationService()in Perl) so that Google Ads authentication andlogin-customer-idheaders are configured automatically, instead of instantiating a standaloneOperationsClient. CallOperations.GetOperation(orOperationService::getin Perl) for a single status check, or use the operation name to resume a long-running operation wrapper and poll until completion (runBatchJobOperationCallable().resumeFutureCallin Java,PollOnceRunBatchJobin C#,resumeOperationin PHP,google.api_core.operation.from_gapicon theOperationreturned byget_operationin Python,wait_until_done!on theGapic::Operationreturned byget_operationin Ruby, ornameinOperationService::poll_until_donein Perl). - REST: Send an HTTP
GETrequest tohttps://googleads.googleapis.com/v26/OPERATION_NAME.
Because
OPERATION_NAMEencodes the API major version in which theBatchJobwas created,Operations.GetOperation(even through the activev26REST endpoint) fails with aRequestError.UNSUPPORTED_VERSIONerror if that version has since sunset. Querybatch_job.statusdirectly withGoogleAdsServiceinstead.- Client libraries: Obtain the operations client from your
Understand operation metadata
When you poll the long-running operation or query the
batch_job resource,
BatchJobMetadata provides details about the batch job's
progress:
creation_date_time: The timestamp when the batch job was created.start_date_time: The timestamp when the batch job started running (populated when you querybatch_job.metadata.start_date_timewithGoogleAdsService; omitted fromOperation.metadatainRunBatchJobandOperations.GetOperation).completion_date_time: The timestamp when the batch job finished (only present if the job is done).estimated_completion_ratio: An estimate of the fraction of the job (from 0.0 to 1.0) that has been completed.operation_count: The total number of operations in the batch job.executed_operation_count: The number of operations that have been executed so far.execution_limit_seconds: The approximate upper bound, in seconds, for how long the batch job can run before being canceled (populated when you querybatch_job.metadata.execution_limit_secondswithGoogleAdsServiceif a positive limit was set at job creation; omitted fromOperation.metadatainRunBatchJobandOperations.GetOperation).
These fields, especially estimated_completion_ratio
and the operation counts, can help you gauge the job's progress, estimate
remaining time, and adjust your polling frequency. For example, you might poll
less frequently when the estimated_completion_ratio
is low, and more frequently as it approaches 1.0.
List all batch job results
When the batch job finishes, call
ListBatchJobResults to retrieve the status and
response for each operation in the job:
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}"
In ListBatchJobResultsRequest, the
page_size field defaults to the maximum value of 1000 if
omitted or set to 0. Setting page_size to a value greater than
1000 or less than 0 returns a
BatchJobError.INVALID_PAGE_SIZE error.
Each BatchJobResult identifies the corresponding operation
using operation_index, the 0-based index of the
uploaded MutateOperation in the batch job.
- Successful operation:
mutate_operation_responseis populated (itsresponsecontains the mutated resource'sresource_name, plus all mutable fields ifresponse_content_typeis set toMUTABLE_RESOURCE), andstatusis unset. - Failed (or unexecuted) operation:
mutate_operation_responseis unset, andstatuscontains the error details for the operation.
Cancel or remove a batch job
How you stop or discard a batch job depends on whether
RunBatchJob has been called:
- Before you call
RunBatchJob: While the job'sstatusisPENDING, you can discard the batch job by callingMutateBatchJobwithBatchJobOperation.remove. Callingremoveafter the job starts running returns aBatchJobError.CAN_ONLY_REMOVE_PENDING_JOBerror. - After you call
RunBatchJob: You cannot manually cancel a running batch job (Operations.CancelOperationis not implemented in the Google Ads API and returnsUNIMPLEMENTED). To bound execution time so a job cancels automatically if it runs too long, setmetadata.execution_limit_secondsto a positive integer (an approximate upper bound) when you create the job inMutateBatchJob. Because standard operations in a batch job execute with partial failure enabled (operations in atomic sub-batches are rolled back together), automatic cancellation does not roll back operations that have already completed. Once a canceled (or aborted) job'sstatustransitions toDONE, callingListBatchJobResultsreturnsBatchJobResultentries for the executed prefix (operation_index<executed_operation_count) with their individual execution outcomes, followed byBatchJobResultentries for all remaining unexecuted operations (operation_indexfromexecuted_operation_countthroughoperation_count- 1) withmutate_operation_responseunset andstatusset toABORTEDwithInternalError.INTERNAL_ERRORwhen canceled due toexecution_limit_seconds(or to the job-level error status if the job aborted due to a fatal execution error).
Error handling
BatchJobService executes standard operations with
partial failure enabled (successful operations commit even
if other operations in the same job fail, except within
atomic sub-batches) and automatically retries
operations that fail due to transient errors. However, not all failure scenarios
can be avoided. Operations that failed due to validation errors can be fixed and
resubmitted in a new batch job. Likewise, when a batch job is
canceled or aborts before it completes all operations, you can
resubmit the unexecuted operations (operation_index
>= executed_operation_count) along with any failed
operations from the executed prefix in a new batch job.