App Engine,交易和幂等 [英] App Engine, transactions, and idempotency

查看:151
本文介绍了App Engine,交易和幂等的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请帮我看看我的误解。



我正在App Engine上撰写角色扮演游戏。玩家采取的某些行动消耗某些属性。如果统计数字达到零,玩家可以不采取更多行动。然而,我开始担心作弊的球员,如果一名球员非常快速地发出两个动作,那么彼此相邻?如果减少属性的代码不在交易中,那么玩家有可能执行两次动作。所以,我应该包装在交易中减少stat的代码,对吧?到目前为止,这么好。



然而,在GAE Python中,我们在 documentation
$ b


注意:如果您的应用程序在提交事务时收到异常,它不会
总是表示事务失败。在事务已经提交的情况下,您可以收到Timeout,TransactionFailedError或
InternalError异常,并最终成功应用
。只要有可能,使您的数据存储交易幂等因此
,如果您重复交易,最终结果将是相同的。


哎呦。这意味着我运行的函数如下所示:

  
def decrement(player_key,value = 5) :
player = Player.get(player_key)
player.stat - = value
player.put()

呃,这不会奏效,因为这个东西不是幂等的,对吧?如果我在它周围放置一个重试循环(是否需要使用Python?我读过,我不需要这么做,但是我无法在文档中找到它),它可能会增加两次值,对?由于我的代码可以捕获异常,但数据存储区仍然提交数据......呵?我该如何解决?这是我需要分布式交易的情况吗?我真的吗?

解决方案

首先,Nick的答案是不正确的。 DHayes的交易不是幂等的,所以如果它运行多次(即第一次尝试被认为是失败的时候重试),那么这个值将被多次递减。尼克说,数据存储检查实体是否被修改后,但这并不能阻止这个问题,因为两个事务有单独的提取,第二个提取是在第一个事务完成后。



为了解决这个问题,您可以通过创建一个交易密钥并将该密钥记录在一个新实体中作为交易的一部分来使交易幂等。第二个事务可以检查该事务密钥,如果找到,将不会执行任何操作。交易密钥可以删除,一旦你确信交易完成,或者你放弃重试。



我想知道非常罕见意味着什么AppEngine(百万分之一,还是十亿分之一?),但我的建议是,财务事宜需要幂等交易,但不是游戏分数,甚至是生命; - p>

Please help me find my misunderstanding.

I am writing an RPG on App Engine. Certain actions the player takes consume a certain stat. If the stat reaches zero the player can take no more actions. I started worrying about cheating players, though -- what if a player sent two actions very quickly, right next to each other? If the code that decrements the stat is not in a transaction, then the player has a chance of performing the action twice. So, I should wrap the code that decrements the stat in a transaction, right? So far, so good.

In GAE Python, though, we have this in the documentation:

Note: If your app receives an exception when submitting a transaction, it does not always mean that the transaction failed. You can receive Timeout, TransactionFailedError, or InternalError 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.

Whoops. That means that the function I was running that looks like this:


def decrement(player_key, value=5):
  player = Player.get(player_key)
  player.stat -= value
  player.put()

Well, that's not gonna work because the thing isn't idempotent, right? If I put a retry loop around it (do I need to in Python? I've read that I don't need to on SO... but I can't find it in the docs) it might increment the value twice, right? Since my code can catch an exception but the datastore still committed the data... huh? How do I fix this? Is this a case where I need distributed transactions? Do I really?

解决方案

First, Nick's answer is not correct. DHayes's transaction is not idempotent, so if it's run multiple times (ie. a retry when the first attempt was thought to have failed, when it didn't), then the value will have been decremented multiple times. Nick says that "the datastore checks if the entities have been modified since they were fetched", but that doesn't prevent the problem since the two transactions had separate fetches, and the second fetch was AFTER the first transaction completed.

To solve the problem, you can make the transaction idempotent by creating a "transaction Key" and recording that key in a new entity as part of the transaction. The second transaction can check for that transaction key, and if found, will do nothing. The transaction key can be deleted once you're satisfied that the transaction completed, or you give up retrying.

I'd like to know what "extremely rare" means for AppEngine (1-in-a-million, or 1-in-a-billion?), but my advice is that idempotent transactions is required for financial matters, but not for game scores, or even "lives" ;-)

这篇关于App Engine,交易和幂等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆