Thank you Helge!

Please let me clarify…

Are you saying that even if the db.get(key_of_marker) returns None in step 1, 
step 5 will return an exception if an entity of the same key was created in 
another transaction that happened between steps 2 - 4 of the original 
transaction?

Is the following Transaction A doomed to fail?


Transaction A

# Check Marker to see if this transaction has been done before
if db.get(db.Key().from_path('Marker', 'abcdefg')):
        return

# Perform other db operations here…

# CONCURRENTLY, Transaction B happens and completes here...

# Set Marker specific to this transaction to avoid repeats
Marker(key_name='abcdefg').put()

return


Transaction B

Marker(key_name='abcdefg').put()

return


I just want to be 100% certain that my transactions either completely fail or 
completely succeed AND NEVER EVER repeat.

Do you think the above algorithm will fit my requirements?

Thanks! I appreciate this so much.


Albert
On June 12, 2013 at 5:58:19 PM, Helge Tesdal ([email protected]) wrote:
Step 1 Will not return None if a previous transaction created the entity (that 
transaction might seem to have failed though)

Because datastore is using optimistic currency control (not locking), another 
transaction might also write the_key_of_the_transaction_marker somewhere 
between 1 and 5. In that case, 5 will raise an exception on write because it 
notices that the timestamp of the_key_of_the_transaction_marker did not match 
what was read in 1.

It is important to let that exception abort the transaction. Open try/excepts 
are dangerous in this setting.


On Wed, Jun 12, 2013 at 2:19 AM, Albert Padin <[email protected]> wrote:
First, thanks so much for your replies.

To add clarity, this is my situation:

I'm performing a transaction operation that's not idempotent. Therefore, I need 
to know whether it succeeded or not, and I have to be completely certain about 
it (before retrying if it failed). Fortunately, I can generate an id unique for 
each operation. So what I do is I run the following transaction via 
db.transactional(xg=True):

1. db.get(the_key_of_the_transaction_marker)
2. if the the transaction marker exists, then just return. We don't have to 
continue because it's already been done
3. if it doesn't exist, proceed….
4. perform non idempotent modifications here…
5. create transaction marker for this transaction via db.put(). with key set to 
the specific marker/id for this set of modifications

I use step 1 and step 5 to ensure that the operation can never be run twice. 
It's ok for my operation to fail completely. However, it's completely 
unacceptable for it to run twice.

Now, if it's possible for the db.get() in step 1 to return None even if a 
previous transaction had already created that entity (in its own step 5), then 
my "repeat transaction catcher" is useless. Hence, I'm looking for 
clarification regarding this…

Does this make sense?

Thanks so much!


Albert

On June 12, 2013 at 2:21:59 AM, Alex Burgel ([email protected]) wrote:
On Tuesday, June 11, 2013 2:04:17 PM UTC-4, Vinny P wrote:
If a transaction exception occurs though (as you asked in your original post) 
there is no guarantee that the transaction occurred. In that case, you may 
receive stale data because the transaction is delayed/never occurred.

There is no guarantee that the transaction occurred, but if it did occur then 
you will see the latest data. That is because any read/write/new transaction to 
that entity group forces any unapplied transactions to apply before returning 
data. The 'delayed' thing you're referring to only applies to non-ancestor 
queries.

>From another developer article: "However, even if it is not completely 
>applied, subsequent reads, writes, and ancestor queries will always reflect 
>the results of the commit, because these operations apply any outstanding 
>modifications before executing." [1]

[1] https://developers.google.com/appengine/articles/transaction_isolation

--  
You received this message because you are subscribed to a topic in the Google 
Groups "Google App Engine" group.
To unsubscribe from this topic, visit 
https://groups.google.com/d/topic/google-appengine/rLsWMWS5Acc/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to 
[email protected].

To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-appengine?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

--  
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-appengine?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--  
Helge Tesdal
Senior Developer - mCASH Norge AS
+47 815 10 150
http://mCA.SH

--  
You received this message because you are subscribed to a topic in the Google 
Groups "Google App Engine" group.
To unsubscribe from this topic, visit 
https://groups.google.com/d/topic/google-appengine/rLsWMWS5Acc/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to 
[email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-appengine?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-appengine?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to