The latest documentation here http://code.google.com/appengine/docs/java/datastore/transactions.html states: "If your app receives an exception when submitting a transaction, it does not always mean that the transaction failed. You can receive DatastoreTimeoutException, ConcurrentModificationException, or DatastoreFailureException exceptions in cases where transactions have been committed and eventually will be applied successfully. Whenever possible, make your Datastore transactions idempotent so that if you repeat a transaction, the end result will be the same."
- How is it possible to know if a transaction succeeded or not?
- What am I going to do after catching ConcurrentModificationException? How do I know if I have to retry?
- How would you recommend making, for example, payment transactions idempotent without any idea whether it was successful?
Few notes:
As docs say - you can not be sure if transaction was applied. That is the core of the problem.
Just rollback in case of all exceptions. See this example: http://code.google.com/appengine/docs/java/datastore/transactions.html#Isolation_and_Consistency
Make it idempotent - meaning if you invoke it twice, it does not matter. In the case of payment transactions, you make "payment transaction" entity. For every transaction you make a special entity with payment data and write it to datastore. The key here is to generate a natural ID from payment data: user ID, source account, payment amount, target account, date/hour/minute. Then if transaction is repeated, it will create a payment transaction entity with the same ID and will overwrite the old one - which means the result will be the same if only one or two transactions were completed. (The balance of the user account is then calculated by going through a series of transactions and adding it to the opening amount - this is what banks actually do in practice AFAIK).