The documentation for GAE's Task Queue API states:
You can enqueue a task as part of a datastore transaction, such that the task is only enqueued—and guaranteed to be enqueued—if the transaction is committed successfully.
However, the documentation for datastore transactions states twice that we should make them idempotent whenever possible, and submitting to a task queue is not idempotent. The documentation for objectify takes this a step further, explaining that work MUST be idempotent within its transactions.
So, is there a standard way to handle combining these recommendations/requirements, or should I roll my own technique (perhaps using something like this)?
DatastoreFailureException, but then succeeds anyway, so the task is enqueued. Objectify retries the transaction, and it succeeds again. Now your task has been enqueued twice, because enqueuing a task is not idempotent. - Eric Simonton