当异步放置时,在请求结束后,在使用NDB的Appengine上导致争用异常会发生什么?

时间:2012-09-01 04:32:22

标签: google-app-engine app-engine-ndb

使用ndb,假设我put_async'd 40个元素,@ ndb.toplevel,向用户写了一个输出并结束了请求,但是其中一个put_async导致了争用异常,响应是500还是200?或者让我们说如果它是一个任务,那么任务会被重新执行吗?

一个解决方案是get_result()在请求结束之前查看所有这40个请求并捕获这些异常 - 如果它们发生 - 但我不确定它是否会影响性能。

2 个答案:

答案 0 :(得分:4)

据我所知,使用@ ndb.toplevel会导致处理程序在退出之前等待所有异步操作完成。 来自文档:

  

为方便起见,您可以使用@ ndb.toplevel修饰请求处理程序。这告诉处理程序在异步请求完成之前不要退出。这反过来让您发送请求,而不用担心结果。 https://developers.google.com/appengine/docs/python/ndb/async#intro

因此,通过添加@ndb.toplevel,在异步方法执行完毕之前,实际上不会返回响应。使用@ ndb.toplevel不需要在所有被触发的异步调用上调用get_result(为方便起见)。 基于此,如果异步查询失败,请求仍将返回500,因为在返回之前需要完成所有异步查询。 更新:下面

如果使用任务(我假设您的意思是任务队列),任务队列将在请求失败时重试请求。 所以你的处理程序可能是这样的:

def get(self):
    deferred.defer(execute_stuff_in_background, param,param1)
    template.render(...)
一旦处理程序返回,

和execute_stuff_in_background将执行所有昂贵的put。如果任务中存在争用问题,则原始处理程序仍将返回200。

如果您怀疑存在争用问题,可以考虑使用分片或使用fork-join队列实现来处理写入(请参阅此处的实现:http://www.youtube.com/watch?v=zSDC_TU7rtc#t=41m35

编辑:简短回答 如果异步请求失败,请求将失败(返回500),因为@ ndb.toplevel等待 在退出之前完成所有结果。 更新:看了@ alexis的答案后,我重新运行了我的原始测试(我关闭了数据存储区写入并在装有@ndb.toplevel的处理程序中调用了put_async),响应间歇性地提高了500 (我认为这取决于执行时间)。基于此和@ alexis的答案,如果异步任务抛出异常并且调用函数用@ ndb.toplevel

修饰,则不要期望结果为500

答案 1 :(得分:3)

这很奇怪,我使用顶层并期望相反的行为。这就是我观察到的。自第一个回答这个问题以来,有什么变化吗? 正如医生所说:

  

这反过来让你发送请求而不用担心   结果

您可以尝试以下unittest(使用testbed):

@ndb.tasklet
def raiseSomething():
    yield ndb.Key('foo','bar').get_async()
    raise Exception()

@ndb.toplevel
def callRaiseSomething():
    future = raiseSomething()
    return "hello"

response = callRaiseSomething()
self.assertEqual(response, "hello")

此测试通过。 NDB记录一个警告:“暂停生成器raiseSomething(tests.py:90)引发Exception()”,但它不会重新引发异常。

ndb.toplevel只等待RPC,但不执行任何实际结果。 如果你的装饰函数本身就是一个tasklet,它会先调用get_result()。此时将提出异常。然后它将等待剩余的“孤立”RPC,并且只会在引发异常时记录某些内容。

所以我的回答是:请求会成功(返回200)