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
complete" marker entity to the picture that gets written in the same
transaction as the run-once operation, does that cover all the bases? The
marker would still need to be cleaned up at some later point, of course.
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/-/Mamb76pc7akJ.
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.