【问题标题】:How can you use async apis with ndb hooks?如何使用带有 ndb 钩子的异步 api?
【发布时间】:2018-03-09 11:40:55
【问题描述】:

我有一些钩子,我想我可以用@ndb.tasklet 装饰它们,以便在钩子中使用异步api。 例如

@classmethod
@ndb.tasklet
def _post_delete_hook(cls, key,future):
    yield do_something_async()

这个似乎可以工作,但我时不时地看到这些钩子内的代码出现“暂停生成器”错误。

我应该改用@ndb.synctasklet 吗?

错误示例:

suspended generator _post_put_hook(data_field.py:112) raised TypeError(Expected Future, received <class 'google.appengine.api.apiproxy_stub_map.UserRPC'>: <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x09AA00B0>)

偶尔导致错误的代码是:

           t, d = yield (queue.add_async(task), queue.delete_tasks_async(taskqueue.Task(name=existing_task_name)))

现在我已经输入了@ndb.synctasklet,它引发了一个实际的异常。

【问题讨论】:

  • 你能显示这样(完整的)暂停生成器错误吗?它们可能无关...
  • @DanCornilescu 谢谢,已更新。
  • 认为该消息可能表明在为异步操作创建 Future 时遇到错误。您正试图在该收益率中一次创建 2 个期货 - 情况是否如此,或者有时可能只有其中一个?您可以添加检查以查看是否正确创建了每个未来吗?大部分时间都是在黑暗中拍摄,到目前为止,我并没有玩太多的小任务。
  • @DanCornilescu 谢谢。我现在将它们分成 2 个单独的产量(不理想)。我再也没有看到错误。我认为该错误是由 delete_tasks_async 引发的。不过,我的主要问题是将其装饰为 ndb.tasklet 或 ndb.synctasklet 是否正确。 ndb.tasklet 似乎将错误排除在外
  • 我不建议使用 2 个 yield 操作,只需将每个 *_async 调用分配给一个变量,检查变量并仅生成有效变量。

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


【解决方案1】:

ndb tasklet 返回一个未来。如果调用 tasklet 导致异常,只有调用 future 的 get_result 方法时才会引发异常。

ndb.synctasklet 自动在 tasklet 产生的期货上调用 get_result,从而在发生异常时引发异常,而不仅仅是记录。

对于您看到的错误,您可以通过将任务队列异步方法返回的 UserRPC 转换为小任务来修复它。

此未经测试的代码基于ndb.context.urlfetch (link),它将urlfetch.createRPC 生成的UserRPC 转换为Future

  @ndb.tasklet
  def add_async(queue, **taskqueue_kwargs):
      rpc = queue.add_async(**taskqueue_kwargs)
      result = yield rpc
      raise ndb.Return(result)

您需要为每个要使用的异步方法创建一个 tasklet,或者您可以扩展 taskqueue 类并使异步方法成为 tasklet。

【讨论】:

  • 不就是和result = yield queue.add_async()一样吗?任务队列问题是次要的,主要关心的是 post_put_hooks/deletes/gets 是否可以是@nbd.tasklets。
猜你喜欢
  • 2021-03-24
  • 1970-01-01
  • 2021-09-05
  • 2022-06-17
  • 2019-11-15
  • 1970-01-01
  • 2013-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多