While most services provide synchronous APIs, requiring you to make a request then wait for a response, MutateJobService provides a way to asynchronously perform operations on multiple services, without tying up your logic.
Unlike service-specific mutate
operations, a single job in
MutateJobService can operate against a mixed collection of campaigns, ad groups,
ads, and criteria. Submitted jobs run in parallel, and there is no limit
to the number of jobs you can submit. However, there is a system rate limit,
and if the job submission rate exceeds the system rate limit, initiation
of ensuing jobs may be delayed.
Supported Operations
The following operation types are supported:
- AdGroupAdOperation
- AdGroupCriterionOperation
- AdGroupOperation
- AdGroupBidModifierOperation
- CampaignCriterionOperation
- CampaignOperation
- AdGroupFeedOperation
- CampaignFeedOperation
- FeedOperation
- FeedItemOperation
- FeedMappingOperation
Using MutateJobService
You can batch up and submit a list of mutate operations to MutateJobService.mutate(). The method will return a SimpleMutateJob with a unique job ID.
After you've submitted all your jobs, you can retrieve their status by
calling
MutateJobService.get()
supplying jobIds
in
BulkMutateJobSelector.
This will return a list of SimpleMutateJob
objects populated with
status, as well as fields of its parent object, Job
. When the
status is COMPLETED
, results are available.
To get the results of a job, pass in a BulkMutateJobSelector
with a single jobId
to the
getResult()
method. For a completed job, this will return a SimpleMutateResult
object containing the list of results corresponding to the submitted
operations. A
PlaceHolder
object is used when a result is unavailable to ensure that the n-th operation
passed to mutate()
conveniently corresponds to the n-th result.
For an uncompleted job, an ApiException
with the
CAN_RETURN_RESULT_FOR_ONLY_COMPLETED_JOBS
reason is returned.
Typically, you should call getResult()
only once. Aggressive
polling with this method is discouraged, especially if it's done in parallel for
several submitted jobs. Use get()
instead to check for job
completion.
Errors are contained in the list of errors, with the index found in the
fieldPath
field and corresponding to the operation index passed to
mutate()
.
Best Practices
Consider these guidelines when usingMutateJobService
:
For better throughput, fewer larger jobs is preferred over many smaller jobs. Once a job is scheduled and is executing, it will proceed rapidly. For best results, pack 5000 operations per job.
When making lots of consecutive calls to
MutateJobService.mutate()
using the same effectivecustomerId
, leave at least two seconds between calls. This suggested interval does not apply to successive calls for differentcustomerId
s, so interleaving of differentcustomerId
s is recommended whenever possible.When submitting a lot of concurrent jobs for the same
customerId
, try to reduce the likelihood of jobs operating on the same AdGroups at the same time, while maintaining large job sizes. Many unfinished jobs (with status ofPENDING
orPROCESSING
) that try to mutate the same set of AdGroups may lead to deadlock-like conditions resulting in severe slow-down and even job failures.When calling
get()
, gather as many of the outstandingjobIds
(for the samecustomerId
) and send them all in the same request. We recommend a polling interval of 30 secs, with exponential backoff.For example,
period_sec = 1.33 ^ n * 30 for n = 0, 1, 2, ...
will generate waits of: 30 sec, 40 sec, 53 sec, 70 sec, ...