google-app-engineasynchronousgoogle-cloud-datastoreapp-engine-ndbtasklet

Using always async ndb operations in ndb gae


I'm developing with gae and ndb and I find that I have to write a lot of code for ndb gets and queries. Sometimes I need two versions (sometimes 3 or more).

Suppose I have the following Models and functions inside them:

class MainEnt(ndb.Model):
    """Main entity. The parent is the user_key"""
    name = ndb.StringProperty()
    child = ndb.KeyProperty()

    def get_created_by(self, user_id):
        """Get the MainEnt's created by user_id"""
        # stuff... getting the query and returning the results

    def get_created_by_async(self, user_id):
        """Get async the MainEnt's created by user_id"""
        # stuff... getting the query async and returning a future

    @ndb.tasklet
    def get_childs_async_tasklet(self, mainent_key):
        """Get async the childs of a MainEnt"""
        # stuff... yielding the query async. and raise ndb.Return()...

    @ndb.tasklet
    def get_created_by_async_tasklet(self, user_id):
        """Get async the MainEnt's created by user_id"""
        # stuff... yielding the query async. and raise ndb.Return()...

    @ndb.tasklet
    def get_created_by_async_tasklet_with_childs(self, user_id):
        """Get async the MainEnt's created by user_id and its childs"""
        # stuff... yielding the query async. calling get_childs.. and raise ndb.Return()...

    @ndb.tasklet
    def get_voted_by_async_tasklet(self, user_id):
        """Get async the MainEnt's voted by user_id"""
        # stuff... yielding the query async raise ndb.Return()...

    @ndb.tasklet
    def get_voted_by_async_tasklet_with_childs(self, user_id):
        """Get async the MainEnt's voted by user_id and it's childs"""
        # stuff... yielding the query async, calling get_childs.. and raise ndb.Return()...

    @ndb.tasklet
    def get_created_and_voted_by_async_tasklet(self, user_id):
        """yield get_created_by_async_tasklet and get_voted_by_async_tasklet in parallel"""
        # stuff... yielding the other two functions and return results...

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

As you see MainEnt have three methods that return the "same" (sometime more) results but are used in different contexts.

1) The sync function only used when I need to get the results and getting that results are the only "ndb operation".

2) The async function only used when I need to get the results but I also perform some other ndb query that I want to overlap.

3) The tasklet async function only used when I need to get the results, get the Child Entities of this results and maybe also performing some other ndb operation.

Because I find writing too many functions...It's correct to only write an async tasklet function that is going to be called in each of the previous situations??

I mean even if I just need the results synchronous I will call the get_created_by_async_tasklet and then call get_results on the future returned by the function.

Is there any inconvenience on performance, error prone, etc... into doing this? I find out much more simple to always use an ndb async tasklet for every query, get, etc... and only call its results if I need too or otherwise perform more async operations and later call get_results.

Hope this is well explained...

Thanks in advance!


Solution

  • There is nothing wrong with only using async calls, then using get_result immediately if you want the results syncronously. This is exactly what the ndb synchronous functions do:

    Here is an example from ndb.Key:

    def get(self, **ctx_options):
        """Synchronously get the entity for this Key.
    
        Return None if there is no such entity.
        """
        return self.get_async(**ctx_options).get_result()