【发布时间】:2014-01-11 09:59:51
【问题描述】:
我在一个方法中有以下一段代码,它被装饰为事务性的:
@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”开始。
我通过按时间戳对调试语句进行排序来验证这一点。
当然,由于这个问题,计数器达到 0 的速度太快了。 open_enrichments 最初设置为 8,但(对于使用 key.get() 读取计数器的其他任务有效)减少了 12 或 13 倍,从我在 NDB 中了解的事务中我不明白。
编辑:
为了澄清顺序:
- 任务 A 使用 open_enrichments = 5 输入这段代码
- 任务 A 将这段代码保留为 open_enrichments = 4 并失败,因为在此期间
- 任务 B 使用 open_enrichments = 4(不是 5)输入了这段代码!!!! 似乎 >>thing = tkey.get()
- 任务 B 将这段代码保留为 open_enrichments = 3 并成功提交
- 任务 A 以 open_enrichments = 3 重新输入这段代码
- 任务 A 将这段代码保留为 open_enrichments = 2 并提交
所以这两个任务只成功运行了两次,但是计数器减了 3 !!
【问题讨论】:
-
任务是否因事务之外的原因而失败并重试?
-
失败的不是任务,而是方法(因为事务方法的一个实例与另一个任务中的另一个实例“冲突”)。所以该方法被重试 - 最多 2 次 @decorator 指定的。
-
我认为您需要使用父/祖先来实现强一致性:developers.google.com/appengine/docs/python/datastore/…
-
好吧,如果我使用这种方法......这个组中的所有实体(行)都属于“每秒少于 1 次写入操作”的规则,这是一个相当严格的限制,如果你有几百个你正在处理并发任务的实体。
-
你怎么知道任务 A 失败了?日志条目不会告诉你,时间不会一致。即:如果任务A进入离开,然后任务B进入离开,日志条目可能是任务A进入,任务B进入,任务A离开,任务B离开。
标签: python google-app-engine transactions google-cloud-datastore