2
votes

I am not sure how to handle asynchronous operation in Google App Engine. Can you help me with this code?

I want to put asynchronously entity:

class Thing(ndb.Model):
  pass

entity = Thing()
future = entity.put_async()

# hundred of code lines of other async to parallelize

But I am not sure if I should wait on this put before handlers ends?

Should I finish my code with to keep data consistent?

future.wait()

Maybe my question looks trivial but I want avoid random bugs from unpredicted behavior. I read https://cloud.google.com/appengine/docs/python/ndb/futureclass but not found good answer here.

Same here https://cloud.google.com/appengine/docs/python/ndb/async.

2
Why would you use an async method if you are going to wait for it to finish anyway?Tim
@TimCastelijns Because I want use put_async() not put(). Code is simplified. Do not think that I do not know how to use put() assume that I have to use put_async() and hundred of code lines is skipped.Chameleon

2 Answers

3
votes

You can use ndb.toplevel()

From the docs:

In this example (and your code), it's a little silly to call future.get_result: the application never uses the result from NDB. That code is just in there to make sure that the request handler doesn't exit before the NDB put finishes; if the request handler exits too early, the put might never happen. 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. This in turn lets you send off the request and not worry about the result.

You can specify a whole WSGIApplication as ndb.toplevel. This makes sure that each of the WSGIApplication's handlers waits for all async requests before returning. (It does not "toplevel" all the WSGIApplication's handlers.)

Example:

app = ndb.toplevel(webapp2.WSGIApplication(routes=routes, debug=True))
2
votes

You should wait for completion if you want to handle any failures.

If you can afford loosing some entities (usually it would be very small percentage but in case of data center issues can grow dramatically to 100% for some time) you can fire async operation and forget it. There is a hidden catch though - I was not able to find a link now but I remember it was told that GAE would wait for all futures to be completed before returning a response to client. That's something that needs to be tested.

You can accumulate futures in a list and then call Future.wait_all(futures) in the end of your process. Put in a try:except block and when got an exception check status of each future and handle as needed.