Search code examples
pythontornadoyield

Refactoring a Tornado Request Handler


So I have repeating code that I do for many GETs -- checking whether the response was cached previously and returning that if it is available.

The code I'd like to get working looks like this:

class Handler(web.RequestHandler):

    @gen.coroutine
    def get_cache(self):
        try:
            response = yield gen.Task(get_redis)
        except:
            logging.log()
        if response:
            self.finish(response)
            raise gen.Return()


    @gen.coroutine
    @asynchronous
    def get(self):
        self.get_cache()

        response = do_sql_get()

        self.set_cache(key, response)
        self.finish(response)

What's happening now is that it gets the cache if there but continues running the rest of the code in self.get. That it does this makes sense to me, but I'm not sure how to refactor it properly with it stopping as soon as self.finish is called in the self.get_cache method.


Solution

  • get_cache should return a value that indicates whether it finished the request or not (or it should return the cached data and leave it to the caller to finish the request). I would do one of the following:

    @gen.coroutine
    def serve_from_cache(self):
      response = yield gen.Task(get_redis)
      if response:
          self.finish(response)
          raise gen.Return(True)
      else:
          raise gen.Return(False)
    
    @gen.coroutine
    def get(self):
      if (yield self.serve_from_cache()):
        return
      # do work
      yield self.set_cache(...)
    

    or

    @gen.coroutine
    def get_cache(self):
        return yield gen.Task(get_redis)
    
    
    @gen.coroutine
    def get(self):
        resp = yield self.get_cache()
        if resp:
          self.finish(resp)
          return
        # do work...