Search code examples
pythonasynchronoustornado

Encapsulating asynchronous actions in functions


I've faced an ambiguous situation with asynchronous functions in Tornado.

The system I've been working on receives only POST requests and serves them asynchroniously. But now i must add GET request handling for serving IE8 users. The problem is that GET request functionality is exactly the same as in post request.

I don't want co simply copy-paste my code, so i've came to the following solution:

class ExampleHandler(BaseHandler):

    def _request_action(self):
        """ Function that incapsulates all actions, that should be performed in request
        """
        yield self.motor.col1.insert({"ex1": 1})
        raise Return

    @gen.coroutine
    def get(self):
        """ GET request handler - need for IE8- users. Used ONLY for them
        """
        self._request_action()

    @gen.coroutine
    def post(self):
        """ POST handling for all users, except IE8-
        """
        self._request_action()

I have a lot of doubts about async decorators. Is it enough to wrap GET/POST handlers in decorators, and put all actions that should be performed in a synchronously working function? Or i should wrap it too?


Solution

  • If you yield a Future inside a function, you have to wrap it with @gen.coroutine.

    So, wrap _request_action with @gen.coroutine

    @gen.coroutine
    def _request_action(self):
        """ Function that incapsulates all actions, that should be performed in request
        """
        result = yield self.motor.col1.insert({"ex1": 1})
        raise gen.Return(result)  # that is how you can return result from coroutine
    

    And also, all coroutines must be called by yield:

    @gen.coroutine
    def get(self):
        """ GET request handler - need for IE8- users. Used ONLY for them
        """
        result = yield self._request_action()
        # do something with result, if you need
    
    @gen.coroutine
    def post(self):
        """ POST handling for all users, except IE8-
        """
        result = yield self._request_action()
        # do something with result, if you need