Discover v2009: Error handling in BulkMutateJobService.

Wednesday, April 28, 2010


In our previous blog post, we discussed how v2009 error handling works in synchronous APIs. In this blog post, we cover asynchronous error handling in BulkMutateJobService. If you are new to BulkMutateJobService, check out our introductory blog post and code.google.com article.

Due to its asynchronous nature, error handling in BulkMutateJobService is slightly different than in other services. Instead of throwing an ApiError object, BulkMutateJobService returns FailureResult or BatchFailureResult objects as its operation results. These objects in turn contain the relevant ApiErrors. BulkMutateJobService processes the operations within an operation stream in multiple atomic batches. If there is even one faulty operation in a batch, it causes the other non-faulty operations in the batch to fail as well. When a batch of n operations fails, you will get one FailureResult and n - 1 BatchFailureResults as results for the failed batch of operations. The FailureResult object will always be first in the batch, and will contain one ApiException object. The ApiException contains all the errors for the entire batch of operations, just like for other services. This will be followed by n - 1 BatchFailureResults, which can be viewed as placeholders, one for each operation in the batch.

For instance, assume that you are trying to create the following 9 text ads in a single OperationStream. For the purposes of this example, assume that the system processes operations in batches of 3. The errors are highlighted in red.



































































IndexAdDestination UrlError
0New York Budget Hotel
Clean and close to subway.
Students save 20%!
www.example.com/NewYork
http://www.example.com/NewYork

1Book New York Hotel Deals
Research your New York Stay. Deals
up to 70% from example.com.
www.example.com/NewYork
http://www.example.com/NewYork

2Hotels In New York
Book your hotel room online at a
lower price via example.com!!
www.example.com/NewYork
http://www.example.com/NewYork
Excessive punctuation in description2
3Manhattan Best Hotel
Experience the Best of Manhattan
For Rates As Low As $239/Night.
www.example.com/NewYork
www.example.com/NewYork
Missing schema in destination url.
4New York City Hotels Discount
Discounted Rooms in New York City.
Get Lowest Rates Available Today.
www.example.com/NewYork
http://www.example.com/NewYork

5New York City Hotels
Stay Smart in New York NY.
Free internet & breakfast bar.
www.example.com/NewYork
http://www.example.com/NewYork

670% Off New York Hostels
Why Pay More? From $10 We Guarantee
Lowest Prices - From 1 Night
www.example.com/NewYork
http://www.example.com/NewYork

7Stylish New Hotel in NYC
Enjoy Four-Star Amenities & Service
Chelsea/Fashion District. Book Now!
www.example.com/NewYork
http://www.example.com/NewYork

8Budget Lodging in NYC
Comfortable, Clean Modern Economy
Hotel.Great Downtown Location!
www.example.com/NewYork
http://www.example.com/NewYork





When BulkMutateJobService processes these operations, it will return the following results:


Result[0]: FailureResult.
ApiException.errors has one ApiError
PolicyViolationError @ operations[2].operand.ad.description2
Result[1]: BatchFailureResult, operationIndexInBatch = 1
Result[2]: BatchFailureResult, operationIndexInBatch = 2

Result[3]: FailureResult.
ApiException.errors have 1 ApiError
AdError.URL_NO_SCHEME @ operations[0].operand.ad.url
Result[4]: BatchFailureResult, operationIndexInBatch = 1
Result[5]: BatchFailureResult, operationIndexInBatch = 2

Result[6]: ReturnValueResult, successfully created Ad.
Result[7]: ReturnValueResult, successfully created Ad.
Result[8]: ReturnValueResult, successfully created Ad.

As shown in the results above, there is a 1:1 correspondence between the number of operations and number of results. You can get the successful operations by scanning the return value for results which are not FailureResult or BatchFailureResult (operations 6, 7 and 8 in this case). Then, scan through the results to locate FailureResult objects (which always appear at the beginning of the failed batch) to get the operation that actually failed (operations 2 and 3 in this case). You can now pick the failed operations that do not correspond to the ones obtained from FailureResult, and make a new job for them (0, 1, 4, 5). Note that the OGNL path in FailureResult is relative to the batch and not the operationstream, so you have to offset it by the index of FailureResult to get the failed operation (e.g. Results[3] is a FailureResult and its OGNL path is operations[0].operand.ad.url, so the failing operator in the original list is 3 + 0 = operations[3]).

A BulkMutateJob may also return the following error results, even though they're not common:

LostResult: This happens when BMJS has lost results for some of a job's operations. You can recover from this error by checking numFailedOperations and numUnprocessedOperations for the job. If both are zero, or if the number of errors in ApiError matches numFailedOperations, then the operations were successful, but the results are missing. In any other case, you have to retrieve the entities that were targeted by the operations and see if the operation actually succeeded or not.

UnprocessedResult: This indicates that the mutate operation was not processed. This could happen because the workflow implementation prevented the operation from being processed (e.g. the operations exceed API quota). You can recover from this issue by checking the job status, making sure that you have sufficient API quota left, and simply retrying the operations in a new job.

In an upcoming blog post, we will cover the most common errors you may get in v2009, and how to address them. We've included support for error handling in all of our client libraries to help get you started, so please try it out and share your feedback with us on the forum or the projects' issue trackers.

-- Anash P. Oommen, AdWords API Team