Friday, December 31, 2010

Java AppEngine Queue API semantics are dangerous!

Here is the API documentation for the Queue interface in AppEngine:

com.google.appengine.api.taskqueue
Interface Queue


public interface Queue

Queue is used to manage a task queue.

Implementations of this interface must be threadsafe.

Queues are transactional. If a datastore transaction is in progress when add() or add(TaskOptions) is invoked, the task will only be added to the queue if the datastore transaction successfully commits. If you want to add a task to a queue and have that operation succeed or fail independently of an existing datastore transaction you can invoke add(Transaction, TaskOptions) with a null transaction argument. Note that while the addition of the task to the queue can participate in an existing transaction, the execution of the task cannot participate in this transaction. In other words, when the transaction commits you are guaranteed that your task will run, not that your task executed successfully.

 

This API design is WRONG.

I make the argument that if you want your add() to the queue to be part of a transaction, then you should explicitly call the add(Transaction txn, TaskOptions taskOptions) method rather than it just “magically” work. Please don’t do magic behind my back.

If I were forced to be explicit, it would be a much clearer API design. This way you would know exactly what behavior to expect of your code without having to examine the “context” of the rest of your code where your call to add(TaskOptions taskOptions) resides. And heaven help you if your add to a queue resides in another function where an unsuspecting developer cannot immediately “see” there is a transaction context around it. Don’t make this “magically” work with transactions – make us be explicit.

A solid API design should keep developers out of trouble. Didn’t you read, or watch Joshua Bloch on this topic? Google, let’s please nip this one in the bud, even if it means painfully breaking some code living out there. :-)