Reputation: 1093
I am trying to build a caching decorator using redis and the tornadis library for my Tornado route handlers. This is what I have so far:
def rediscache(route):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = yield redis.call("GET", "latest_info")
print(result)
func(*args, **kwargs)
return wrapper
return decorator
Inside my route handler I am using it like so:
class MainHandler(tornado.web.RequestHandler):
def initialize(self, db, redis):
self.db = db
self.quakes = self.db.quakes
self.redis = redis
@gen.coroutine
@rediscache('route_is_here')
def get(self):
''' ... handler logic here ... '''
Problem is that if I use my decorator, I stop seeing output to the web from my handler. If instead of ...
result = yield redis.call("GET", "latest_info")
I do ...
result = redis.call("GET", "latest_info")
Then I start to see output in my browser again but is this the proper way to do it? Is this still asynchronous? If not what is the propper way to do it? Thanks!
Upvotes: 1
Views: 485
Reputation: 12587
Wrapper in your decorator should be gen.coroutine
if you want to yield
coroutines:
def rediscache(route):
def decorator(func):
@tornado.gen.coroutine
@wraps(func)
def wrapper(*args, **kwargs):
result = yield redis.call("GET", "latest_info")
print(result)
if not result:
new = yield func(*args, **kwargs)
# save to
return wrapper
return decorator
You need also change the order of decorators to:
@rediscache('route_is_here')
@gen.coroutine
def get(self):
''' ... handler logic here ... '''
edit
Explanation of the decorators order
@second
@first
def my_func():
pass
is the same as
my_func = second(first(my_func))
So if you want to await (yield) your original get
in decorator, you have to pass coroutine therefore it must be before rediscache
.
More info about decorators - https://wiki.python.org/moin/PythonDecorators
Upvotes: 2