我收到了这个错误:
TransactionFailedError: too much contention on these datastore entities. please try again.
即使我没有做任何交易。导致错误的代码行是
ndb.put_multi(entity_list) # entity_list is a list of 100 entities
这个错误并不经常发生,所以这不是什么大问题,但我很好奇为什么我会收到这个错误。有什么想法吗?
以下是大部分追溯:
Traceback (most recent call last):
...
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 318, in post
self.run_from_request()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 313, in run_from_request
run(self.request.body)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 155, in run
return func(*args, **kwds)
File "/base/data/home/apps/s~opavote/2017-09-15.404125237783169549/tasks.py", line 70, in start_election
models.Voter.create(e.eid, chunk)
File "/base/data/home/apps/s~opavote/2017-09-15.404125237783169549/models.py", line 2426, in create
ndb.put_multi(voters + vbs)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 3958, in put_multi
for future in put_multi_async(entities, **ctx_options)]
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 383, in get_result
self.check_success()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 427, in _help_tasklet_along
value = gen.throw(exc.__class__, exc, tb)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 824, in put
key = yield self._put_batcher.add(entity, options)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 427, in _help_tasklet_along
value = gen.throw(exc.__class__, exc, tb)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 358, in _put_tasklet
keys = yield self._conn.async_put(options, datastore_entities)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 513, in _on_rpc_completion
result = rpc.get_result()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 928, in get_result
result = rpc.get_result()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 613, in get_result
return self.__get_result_hook(self)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1893, in __put_hook
self.check_rpc_success(rpc)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1385, in check_rpc_success
raise _ToDatastoreError(err)
TransactionFailedError: too much contention on these datastore entities. please try again.
答案 0 :(得分:3)
请注意,错误实际上是从RPC响应中的数据存储区本身收到的:self.check_rpc_success(rpc)
。
这使我怀疑在数据存储方面,为了确保支持它的冗余部分的操作一致性/可靠性,每个写操作实际上使用与事务操作相同/类似的机制。不同之处在于,在RPC交换之前/之后,客户端也有一些事务检查,并且可能是数据存储的显式RPC事务开始/结束触发器。
来自Life of a Datastore Write,引用了一些引用一些共同机制的报价,无论交易是否属于交易行为(强调我的):
如果提交阶段成功但应用阶段失败,则 数据存储区将前滚以将更改应用于两个以下的索引 情况:
- 下次在此实体组上执行读取或写入或启动事务时,数据存储区将首先滚动 转发并完全应用此承诺但未应用的写入,基于 日志中的数据。
醇>
失败的一个可能原因是对同一实体的并行访问过多,即使它们只是只读。请参阅Contention problems in Google App Engine,但在这种情况下,他们会在客户端进行交易。
请注意,这只是一个理论;)
答案 1 :(得分:2)
值得重新审核transactions and entity groups,注意各种定义和限制。
提出“每次创建,更新或删除实体的尝试都发生在事务的上下文中”,并且“在单个实体组中,每秒大约有一个事务的写入吞吐量限制,”可能会说你所看到的,特别是如果entity_list
包含属于同一实体组的实体。