У меня есть обработчик запросов, который обновляет объект, сохраняет его в хранилище данных, а затем должен выполнить дополнительную работу перед возвратом (например, постановка в очередь фоновой задачи и json-сериализация некоторых результатов). Я хочу распараллелить этот код, чтобы дополнительная работа выполнялась во время сохранения объекта.
Вот к чему сводится мой код обработчика:
class FooHandler(webapp2.RequestHandler):
@ndb.toplevel
def post(self):
foo = yield Foo.get_by_id_async(some_id)
# Do some work with foo
# Don't yield, as I want to perform the code that follows
# while foo is being saved to the datastore.
# I'm in a toplevel, so the handler will not exit as long as
# this async request is not finished.
foo.put_async()
taskqueue.add(...)
json_result = generate_result()
self.response.headers["Content-Type"] = "application/json; charset=UTF-8"
self.response.write(json_result)
Однако Appstats показывает, что datastore.Put
RPC выполняется последовательно после taskqueue.Add
:
Небольшое копание в ndb.context.py
показывает, что вызов put_async()
в конечном итоге добавляется к AutoBatcher
вместо немедленного выполнения RPC.
Итак, я предполагаю, что _put_batcher
в конечном итоге сбрасывается, когда toplevel
ожидает завершения всех асинхронных вызовов.
Я понимаю, что пакетная установка put имеет реальные преимущества в определенных сценариях, но в моем случае здесь я действительно хочу, чтобы RPC put был отправлен немедленно, чтобы я мог выполнять другую работу, пока сущность сохраняется.
Если я делаю yield foo.put_async()
, то получаю тот же водопад в Appstats, но datastore.Put
выполняется раньше остальных:
Этого следовало ожидать, так как yield
заставляет мой обработчик ждать завершения вызова put_async()
перед выполнением остального кода.
Я также пытался добавить вызов ndb.get_context().flush()
сразу после foo.put_async()
, но вызовы datastore.Put
и taskqueue.BulkAdd
по-прежнему не выполняются параллельно, согласно Appstats.
Итак, мой вопрос: как я могу заставить вызов put_async()
обходить автоматический дозатор и немедленно выдавать RPC?