3

如果我们启动一个事务以删除 appengine 上的一个复杂对象,并且该对象附加了一些需要删除的 blob 引用,那么我们就会遇到问题。如果我们只是删除 blob,事务可能会失败,但 blob 已经消失,因为 blobstore 独立工作(这与事务的想法背道而驰)。

现在我们有了这个很酷的新 NDB,它有一个上下文缓存,没有记录的 API(?)可以解决问题。

工具箱:

  • ndb.get_context() (未在 ndb 的函数参考中记录)
  • ndb_context.call_on_commit(delete_blobs_call_on_commit)

    def delete_blobs_call_on_commit():
       ndb_context = ndb.get_context()
       blobstore.delete(ndb_context.list_of_blobkeys_to_delete)
       # OR: taskqueue.add(url+ndb_context.list_of_blobkeys_to_delete)
    

任务:将事务期间要删除的 blobkey 附加到上下文对象,并在事务后将其删除。

更新: call_on_commit() 不允许数据库操作(可能包括 blobstore.delete,但尚未尝试),并且会抛出 BadRequestError: Cannot start a new operation in a finished transaction,因此唯一的解决方案可能真的是任务队列。

更新:可以从使用 call_on_commit() 注册的函数中调用带有 @ndb.non_transactional 装饰器的函数。因此,可以尝试在提交成功时删除 blob,并希望您没有会导致孤儿的异常。

问题:如何安全地使用上下文缓存?您是如何解决 blob 删除问题的?

4

2 回答 2

1

AFAIK blob 实际上在数据存储中具有表示形式,因此您可以在事务中使用它们。

要安全地使用上下文缓存,请使用带有这些标志的常规模型/密钥 get() 和 put() 操作:use_memcache=False、use_datastore=False、use_cache=True。您还可以将这些标志作为类变量放在模型定义中。

于 2013-07-16T17:24:23.833 回答
0

用 blob 无孤儿删除实体组的一种方法可能是在没有事务的情况下进行可重复的容错删除操作(幂等操作)。

  1. 将实体/祖先标记为已删除,放置(重要的是确保没有人可以再使用它)
  2. 从叶子到父节点的无事务删除
  3. 任何时候发生错误,中止
  4. 用户(看到已删除的项目)或系统(任务队列)可以稍后重试删除
  5. 删除必须能够跳过已经删除的引用才能是幂等的

任何人都可以看到这种方法的问题吗?

于 2013-07-20T12:50:29.640 回答