Yes, I see what you're saying.  But in looking at both your and Robert's 
approaches, I still have questions.

Jeff, how does your approach avoid executing the operation twice?  Let's 
say there's a web page with a submit button that triggers the process, and 
the user clicks that button twice.  The algorithm you outlined...

Create TxnID entity instance
Repeat until success {
 * start txn
 * load TxnID (if null, return success immediately)
 * debit $5 from AccountA
 * credit $5 to AccountB
 * delete TxnID
 * commit txn
} 
 
...if run serially, would do the operation twice, wouldn't it?  The first 
execution would create the TxnID entity, then in the loop, it would load 
that entity successfully, perform the operation, then delete the TxnID 
entity.  Then, when the 2nd button click is handled, the operation would be 
be performed again.

Robert, I didn't quite follow your algorithm.  Does your marker indicate 
that the operation has not yet been performed?  If so, shouldn't 2b say "if 
the marker is *not* found, abort?  Also, is there an implied retry 
mechanism (e.g. a task) encompassing step 2?

It seems to me there are multiple challenges:
1) eliminate the potential of concurrency
2) retry on failure
3) only do the operation once

If we don't eliminate concurrency, then two parallel threads, in the same 
or different instances, could find the operation not yet completed and both 
perform it.   If we don't indicate (by the presence or absence of a marker) 
that the operation has been completed, then two serial executions would 
both perform it.  And if we don't have a retry mechanism, there is a risk 
that the operation won't be performed at all. 

It still seems to me that the task queue approach addresses 1 (by not 
dequeing a task to two handlers simultaneously and also not accepting a 
duplicate task into the queue) and 2 (by automatically retrying on 
failure), but as Jeff pointed out, not 3.  If you add an "operation not 
performed yet" marker entity to the picture that gets deleted in the same 
transaction as the run-once operation, does that cover all the bases? 

Just to make it interesting, what if the operation to be performed once was 
*not* a datastore operation?  What if it was a call to an external system 
(like a credit card processing service)?  You could successfully make the 
external call, but fail to write the "operation complete" entity.

-Andy

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/YU3N7fnt8rAJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to