Please help me find my misunderstanding.
I am writing an RPG in App Engine. The specific actions that the player takes consume a certain stat. If the stat reaches zero, the player can no longer take any action. However, I began to worry about cheating players - what if a player sent two actions very quickly, right next to each other? If the code that reduces the stat is not in the transaction, then the player has a chance to perform the action twice. So, I have to wrap code that reduces the stat in a transaction, right? So far so good.
In GAE Python, we have this in the documentation :
Note If your application receives an exception when sending a transaction, it does not always mean that the transaction failed. You can get Timeout, TransactionFailedError, or InternalError Exceptions in cases where transactions were committed, and ultimately be successfully applied. Whenever possible, make your Datastore transactions idempotent so that if you repeat the transaction, the end result will be the same.
Oops This means that the function I ran looks like this:
def decrement(player_key, value=5): player = Player.get(player_key) player.stat -= value player.put()
Well, that doesn't work, because the thing is not idempotent, right? If I set a loop around it (do I need it in Python? I read that I don’t need it on SO ... but I can’t find it in the docs), it can increase the value twice, right? Since my code might catch the exception, but the data store still passed the data ... eh? How to fix it? Is this the case when I need distributed transactions ? I am really?
source share