Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @ndb.tasklet or @ndb.synctasklet in Google App Engine

I have a POST method which calls a few tasklets. These tasklets do have yields in them, and I do have some x.put_async() in my code. So I don't want it to return before all the async stuff is done. So I decorated all my tasklets, which are just small functions with @ndb.tasklet. Also, on top of my POST method, I have:

@ndb.toplevel
def post(self):

However, in the documentation it states:

But if a handler method uses yield, that method still needs to be wrapped in another decorator, @ndb.synctasklet; otherwise, it will stop executing at the yield and not finish.

Indeed my method has a yield. It's already wrapped in @ndb.tasklet. Do I replace this with @ndb.synctasklet or do I use both (if so how would I use both)?

Also, see this thread which has some relevance. I too noticed an issue where my request would return without any output, but is un-reproducible. It happens every 15 minutes or so of constant use. I had app = ndb.toplevel(webapp2.WSGIApplication([..]) only, but now I've added @ndb.toplevel to the main POST methods, but the issue still persists.

Should I put @ndb.tasklet on top of methods that have just put_async()'s too? (Should I put it on top of every method just to be safe? What are the downsides to this?)

like image 512
Snowman Avatar asked Sep 04 '12 02:09

Snowman


People also ask

What is NDB Tasklet?

An NDB tasklet is a piece of code that might run concurrently with other code. If you write a tasklet, your application can use it much like it uses an async NDB function: it calls the tasklet, which returns a Future ; later, calling the Future 's get_result() method gets the result.

What is NDB Datastore?

The Google Datastore NDB Client Library allows App Engine Python apps to connect to Datastore. The NDB client library builds on the older DB Datastore library adding the following data store features: The StructuredProperty class, which allows entities to have nested structure.


1 Answers

Regarding the handler and using @ndb.toplevel and @ndb.synctasklet: The way I understood it was that you need to use both @ndb.synctasklet and @ndb.toplevel on the handler. All the sub-tasklets only need the @ndb.tasklet decorator. e.g.

class Foo(ndb.Model):
    name = ndb.StringProperty()

    @ndb.tasklet
    def my_async(self):
        ....
        #do something else that yields
        raise ndb.Return("some result")   


@ndb.toplevel
@ndb.synctasklet
def post(self):
    foo = Foo(name="baz")
    yield foo.put_async()
    yield foo.my_async()
    ....

However. looking at the source, it appears that @ndb.toplevel is actually a synctasklet anyway:

def toplevel(func):
  """A sync tasklet that sets a fresh default Context.

  Use this for toplevel view functions such as
  webapp.RequestHandler.get() or Django view functions.
  """

Running a small test with yields in the handler and decorated with @ndb.toplevel still seems to work, and appears that you can remove @ndb.synctasklet from the handler.

Regarding whether you should include @ndb.tasklet on methods that call put_async(): If you're not yielding on the put_async(), then you don't need to include @ndb.tasklet on the surrounding method (@ndb.toplevel will handle getting the results from the put_async())

like image 120
Rob Curtis Avatar answered Oct 24 '22 03:10

Rob Curtis