5

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

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

4

2 回答 2

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 将执行所有昂贵的放置。如果任务中存在争用问题,您的原始处理程序仍将返回 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

于 2012-09-01T10:04:31.670 回答
3

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

这反过来又让您发送请求而不必担心结果。

您可以尝试以下单元测试(使用测试床):

@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 记录一个警告:“suspended generator raiseSomething(tests.py:90) raiseSomething()引发了 Exception()”,但它不会重新引发异常。

ndb.toplevel 只等待 RPC,但对实际结果不做任何事情。如果你的装饰函数本身是一个小任务,它会首先调用 get_result() 。此时将引发异常。然后它将等待剩余的“孤立”RPC,并且只有在引发异常时才会记录一些内容。

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

于 2013-08-15T13:42:16.857 回答