The Google cloud ndb documentation doesn't say much about async operations.
In the old days, I would do this
@ndb.toplevel
@flask.route('/', methods=['GET'])
def page():
for x in xxx:
ndb.put_multi_async([...])
return 'Done', 200
and the toplevel decorator would make sure that my async puts were done.
How do I do this with the latest cloud ndb?
The cloud ndb docs for toplevel say
Use of this decorator is largely unnecessary, as you should be using context() which also flushes pending work when exiting the context.
but it would be helpful to have more clarity. When would it still be necessary to use toplevel?
CodePudding user response:
Personally, I've always been in the habit of calling .get_result()
on my async tasklets/operations, so this is something that I've never actually used.
The only use case i can think of for toplevel
is if you want to force the flush to occur before you reach the end of your request handler (because at the end of your request handler, you should be exiting the context). In the example below, we want the puts in operation_1
to finish before operation_2
begins:
@ndb.toplevel
def operation_1():
for x in xxx:
ndb.put_multi_async([...])
@flask.route('/', methods=['GET'])
def page():
operation_1()
operation_2()
return 'Done', 200
This could be useful for request handlers for Google Cloud Tasks which can run for up to 10 minutes, so you could be doing a bunch of things in there.
CodePudding user response:
As stated in the documentation for the NDB Asynchronous Operation:
As a convenience, you can decorate the request handler with
@ndb.toplevel
. This tells the handler not to exit until its asynchronous requests have finished. ... Using atoplevel
application is more convenient than all its handler functions.
This was convenient when using the NDB Client Library with Python 2, as you've said:
the toplevel decorator would make sure that my async puts were done
Nowadays using the Cloud NDB library, as shown in this answer,
each NDB operation needs to be wrapped in a context manager:
with ndb_client.context(): # <- you need this line cls.get_or_insert('master')
That is why the documentation says that the use of toplevel decorator
is largely unnecessary, as you should be using context()
because context decorator replaced it and it will
flush pending work_ as async operations.
As referred in the Client
NDB documentation:
The context is used to manage the connection to Google Cloud Datastore, an event loop for asynchronous API calls, runtime caching policy, and other essential runtime state.
Finally, as referred in the ndb
Migration notes:
The biggest difference is in establishing a runtime context for your NDB application. The Google App Engine Python 2.7 runtime had a strong assumption that all code executed inside a web framework request-response cycle, in a single thread per request. In order to decouple from that assumption, Cloud NDB implements explicit clients and contexts.