Ho un gestore di richieste che aggiorna un'entità, lo salva nell'archivio dati, quindi deve eseguire un lavoro aggiuntivo prima di tornare (come fare l'accodamento di un'attività in background e serializzazione json di alcuni risultati). Voglio parallelizzare questo codice, in modo che il lavoro aggiuntivo venga eseguito mentre l'entità viene salvata.Come impedire a ndb di eseguire il batch di una chiamata put_async() e rilasciare immediatamente l'RPC?
Ecco ciò che il mio codice del gestore si riduce a:
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)
Tuttavia, Appstats dimostra che la RPC datastore.Put
è stato fatto in serie, dopo taskqueue.Add
:
Un po 'di scavo intorno a ndb.context.py
indica che una chiamata put_async()
finisce per essere aggiunta a un AutoBatcher
anziché all'RPC emesso immediatamente.
Quindi presumo che lo venga scaricato quando lo toplevel
attende che tutte le chiamate asincrone siano complete.
Capisco che il caricamento in serie abbia vantaggi reali in alcuni scenari, ma nel mio caso qui voglio davvero che l'RPC put venga inviato immediatamente, così posso eseguire altri lavori mentre l'entità viene salvata.
Se lo faccio yield foo.put_async()
, tanto sono la stessa cascata in Appstats, ma con datastore.Put
stato fatto prima che il resto:
Questo è da aspettarsi, come yield
rende mio gestore attendere la put_async()
chiamata da completare prima di eseguire il resto del codice.
Ho anche provato ad aggiungere una chiamata a ndb.get_context().flush()
subito dopo foo.put_async()
, ma le datastore.Put
e taskqueue.BulkAdd
chiamate sono ancora non effettuata in parallelo secondo Appstats.
Quindi la mia domanda è: come posso forzare la chiamata a put_async()
per ignorare il batcher automatico e rilasciare immediatamente l'RPC?
È in produzione o locale? – Lipis
È in produzione. –