为您的搜索文档编制索引不是事务性的,但事务性的是将任务推迟到以后运行。
您可以检查您是否与ndb.in_transaction() 进行交易,并且可以像这样轻松地defer 它:
class UserModel(ndb.Model):
...
def _post_put_hook(self, future):
deferred.defer(UserModel.put_search_document,
self.username,
self.version,
_transactional=ndb.in_transaction())
您还需要处理重试和失败。 This excellent article 有完整的演练和解释,包括简单的版本控制以防止失败、重试和脏读。
这里是那篇文章的完整示例代码:
import logging
from google.appengine.api import search
from google.appengine.ext import ndb
from google.appengine.ext import deferred
class UserModel(ndb.model):
username = ndb.StringProperty(required=True)
email = ndb.StringProperty(required=True)
version = ndb.IntegerProperty(default=0)
@classmethod
def put_search_document(cls, username, version):
model = ndb.Key(cls, username).get()
if model:
if version < model.version:
logging.warning('Attempting to write stale data. Ignore')
return
if version > model.version:
msg = 'Attempting to write future data. Retry to await consistency.'
logging.warning(msg)
raise Exception(msg)
# Versions match. Update the search document
document = search.Document(
doc_id = username,
fields=[
search.TextField(name='username', value=model.username),
search.TextField(name='email', value=model.email),
search.TextField(name='version', value=model.version),
])
index = search.Index(name="UserIndex")
index.put(document)
def _pre_put_hook(self):
self.version = self.version + 1
def _post_put_hook(self, future):
deferred.defer(UserModel.put_search_document,
self.username,
self.version,
_transactional=ndb.in_transaction())