Search code examples
pythontornadotornado-motor

Get result from MotorEngine async query


I'm trying to switch MongoEngine with MotorEngine in my Tornado app for the sake of asynchronous DB access and so far I got nowhere.

query

@gen.coroutine
    def get_all_users(self):
        users = yield User.objects.find_all()

handler

class IUser(BaseHandler):
    @asynchronous
    @gen.engine
    def get(self,userId=None, *args, **kwargs):
        try:
            userMethods = UserMethods()
            sessionId = self.request.headers.get('sessionId')
            ret = userMethods.get_all_users()
        except Exception as ex:
            print str(ex)

        self.finish()

When I print ret variable it says <tornado.concurrent.Future object at 0x7fb0236fe450>. If I try to print ret.result() it gets me nowhere.

Any help is appreciated since I'm struggling with everything I guess...


Solution

  • get_all_users needs to return its value somehow. In Python 2.6 or 2.7, generators aren't allowed to use the "return" statement, so coroutines have a special "Return" exception:

    @gen.coroutine
    def get_all_users(self):
        users = yield User.objects.find_all()
        raise gen.Return(users)
    

    In Python 3.3 and later, you can simply "return users".

    Now in "get", calling "get_all_users" only gives you a pending Future, not a value. You must wait for the Future to resolve to a value by yielding it:

    ret = yield userMethods.get_all_users()
    

    For more about calling coroutines from coroutines, see my "Refactoring Tornado Coroutines".

    By the way, you can decorate "get" with just "gen.coroutine", it's more modern than "asynchronous" and "gen.engine", but either style works.