Google App Engine NDB中的交易似乎有副作用

时间:2014-01-11 09:59:52

标签: python google-app-engine transactions google-cloud-datastore

我在方法中有以下代码,它被装饰为事务性的:

@ndb.transactional(retries=2, xg=True)
def add_insights(self, insights, countdown = True, forced_finish = False):
            ...
    thing = tkey.get() ###############
    logging.debug(thing.open_enrichments)
    thing.insights += insight_keys
    if countdown and not forced_finish:
        thing.open_enrichments -= 1
        if thing.open_enrichments < 0:
            thing.open_enrichments = 0
    elif forced_finish:
        thing.open_enrichments = 0
    logging.debug(thing.open_enrichments)
    thing.put() #########################

此方法在许多并发任务中运行,这些任务可能访问NDB中的同一“事物”实体。当我检查日志文件(为了清楚起见简化调试语句)时,似乎即使这个代码在一个任务中失败,另一个任务仍然可能从失败的任务中的递减计数器“open_enrichments”开始。

我通过按时间戳对调试语句进行排序来验证这一点。

当然,由于这个问题,计数器的速度太快了。 open_enrichments最初设置为8但是得到(对于使用key.get()读取计数器的其他任务有效)减少了12或13次,我从NDB中了解的事务中不了解。

编辑:

澄清顺序:

  • 任务A使用open_enrichments = 5
  • 输入此段代码
  • 任务A使用open_enrichments = 4离开这段代码并失败,因为在此期间
  • 任务B使用open_enrichments = 4(不是5)输入这段代码! 似乎&gt;&gt; thing = tkey.get()&lt;&lt;导致已经改变的实体
  • 任务B将此段代码保留为open_enrichments = 3并成功提交
  • 任务A使用open_enrichments = 3
  • 重新输入此段代码
  • 任务A将此段代码保留为open_enrichments = 2并提交

所以这两个任务只成功运行了两次,但计数器减少了3 !!

1 个答案:

答案 0 :(得分:0)

Appengine事务实际上可以提交但仍然失败,并且会被重试(默认情况下为3次)。请参阅this page上的第一个注释。

因此,您的交易是幂等的非常重要。您是否可以将open_enrichments设置为给定数字而不是在事务中递减?