【问题标题】:GAE NDB "Result cannot be set twice" errorGAE NDB“结果不能设置两次”错误
【发布时间】:2016-08-19 08:14:26
【问题描述】:

我打了这个结果不能设置两次在对一堆异步查询执行ndb.Future.wait_all(futures) 时,GAE Ndb 异步查询出现运行时错误。

类似这样的:

futures = []
for item in items:
    item._future_get = MyEntity.query(...).get_async()
    futures.append(item._future_get)

ndb.Future.wait_all(futures)
# ...

wait_all 上失败,结果不能设置两次

在 SO 上没有提及此错误消息。谷歌有 2-3 次提及它可以追溯到 2011 年,但没有明确的解释。

更多信息:

items 是来自先前 fetch 的 ndb 实体。但它们在这里并不重要(至少我认为),因为查询是在 MyEntity 上执行的。我习惯于以这种方式将futures附加到它们所关联的对象上,所以当全部完成后更容易整理。

堆栈跟踪:

  File "/home/my_project/app/main/admin/my_module.py", line 166, in admin_base_cleanup_details ndb.Future.wait_all(futures)
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/tasklets.py", line 350, in wait_all ev.run1()
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/eventloop.py", line 235, in run1 delay = self.run0()
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/eventloop.py", line 197, in run0 callback(*args, **kwds)
INFO     2016-04-26 08:40:04,152 module.py:808] default: "GET /admin/cleanup/details?mode=status HTTP/1.1" 500 -
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/tasklets.py", line 475, in _on_future_completion self._help_tasklet_along(ns, ds_conn, gen, val)
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/tasklets.py", line 386, in _help_tasklet_along self.set_result(result)
  File "/usr/lib/python2.7/google_appengine/google/appengine/ext/ndb/tasklets.py", line 265, in set_result
    raise RuntimeError('Result cannot be set twice.')
RuntimeError: Result cannot be set twice.

更多精度:

  • 是的,它确实发生在 GAE 以及本地开发人员上。

  • 不,它不会每次都失败,但经常失败。

我发现它与来自另一个线程的并发有关。该网页通过 ajax 调用启动了 2 个请求:一个用于带有一些异步调用的更新查询,这将花费相当多的时间,另一个类似于定期状态更新,更快但也具有异步调用。后者失败了,不是总是失败,而是经常失败。从那时起,我避免重叠这两个请求并且它停止失败。这似乎仍然是一个错误,因为重叠请求不是被禁止的。

【问题讨论】:

  • 你没有提到 item 是什么,哪一行得到了异常,所以 _future_get 可以是一个可修改的属性并且项目在项目中重复吗?
  • 您应该包括堆栈跟踪,以及有关item 是什么的更多信息。
  • @Tim 我在最初的问题中添加了更多信息。
  • 问题是间歇性的还是每次都会发生?如果您将其上传到 App Engine 会发生这种情况吗?
  • 另外,您能否将其隔离为我们可以在您的应用程序之外运行的代码块?我在想,如果您的列表中有重复的项目,但唉,没有骰子。所以我很茫然。

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


【解决方案1】:

您正在使用“异步返回第一个查询结果”的 get_async(),而您可能应该使用 fetch_async() 来获取 Future。

https://cloud.google.com/appengine/docs/python/ndb/queryclass#Query_get_async

【讨论】:

  • 我相信 get_async() 确实会返回一个未来,尽管您所指的文档确实没有明确说明这一点。如果它返回的不是一个未来而是一个实体,它怎么会是异步的呢?
  • 你是对的。 ndb.get_async() 确实返回了一个未来。您所描述的问题来源非常有趣。或许研究 tasklet 可以提供更具体的解决方案,而无需避免重叠请求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
相关资源
最近更新 更多