在 Tornado 中处理 Redis 连接的正确方法是什么?(异步 - 发布/订阅) [英] What is the proper way to handle Redis connection in Tornado ? (Async - Pub/Sub)
问题描述
我将 Redis 和 Tornado 应用程序与 asyc 客户端 Brukva 一起使用,当我查看 Brukva 站点上的示例应用程序时,它们正在通过 websocket 中的init"方法建立新连接
I am using Redis along with my Tornado application with asyc client Brukva, when I looked at the sample apps at Brukva site they are making new connection on "init" method in websocket
class MessagesCatcher(tornado.websocket.WebSocketHandler):
def __init__(self, *args, **kwargs):
super(MessagesCatcher, self).__init__(*args, **kwargs)
self.client = brukva.Client()
self.client.connect()
self.client.subscribe('test_channel')
def open(self):
self.client.listen(self.on_message)
def on_message(self, result):
self.write_message(str(result.body))
def close(self):
self.client.unsubscribe('test_channel')
self.client.disconnect()
在 websocket 的情况下很好,但是如何在常见的 Tornado RequestHandler post 方法中处理它,比如长轮询操作(发布订阅模型).我正在更新处理程序的每个 post 方法中创建新的客户端连接,这是正确的方法吗??当我在 redis 控制台检查时,我看到客户端在每次新的 post 操作中都在增加.
its fine in the case of websocket but how to handle it in the common Tornado RequestHandler post method say long polling operation (publish-subscribe model). I am making new client connetion in every post method of update handler is this the right approach ?? When I checked at the redis console I see that clients increasing in every new post operation.
这是我的代码示例.
c = brukva.Client(host = '127.0.0.1')
c.connect()
class MessageNewHandler(BaseHandler):
@tornado.web.authenticated
def post(self):
self.listing_id = self.get_argument("listing_id")
message = {
"id": str(uuid.uuid4()),
"from": str(self.get_secure_cookie("username")),
"body": str(self.get_argument("body")),
}
message["html"] = self.render_string("message.html", message=message)
if self.get_argument("next", None):
self.redirect(self.get_argument("next"))
else:
c.publish(self.listing_id, message)
logging.info("Writing message : " + json.dumps(message))
self.write(json.dumps(message))
class MessageUpdatesHandler(BaseHandler):
@tornado.web.authenticated
@tornado.web.asynchronous
def post(self):
self.listing_id = self.get_argument("listing_id", None)
self.client = brukva.Client()
self.client.connect()
self.client.subscribe(self.listing_id)
self.client.listen(self.on_new_messages)
def on_new_messages(self, messages):
# Closed client connection
if self.request.connection.stream.closed():
return
logging.info("Getting update : " + json.dumps(messages.body))
self.finish(json.dumps(messages.body))
self.client.unsubscribe(self.listing_id)
def on_connection_close(self):
# unsubscribe user from channel
self.client.unsubscribe(self.listing_id)
self.client.disconnect()
如果您提供类似案例的示例代码,我将不胜感激.
推荐答案
有点晚了,我一直在使用 tornado-redis.它适用于 tornado 的 ioloop 和 tornado.gen
模块
A little late but, I've been using tornado-redis. It works with tornado's ioloop and the tornado.gen
module
安装 tornadoredis
可以通过pip安装
pip install tornadoredis
或使用设置工具
easy_install tornadoredis
但你真的不应该那样做.您还可以克隆存储库并提取它.然后运行
but you really shouldn't do that. You could also clone the repository and extract it. Then run
python setup.py build
python setup.py install
连接到redis
以下代码位于您的 main.py 或等效文件中
The following code goes in your main.py or equivalent
redis_conn = tornadoredis.Client('hostname', 'port')
redis_conn.connect()
redis.connect 只调用一次.它是一个阻塞调用,因此应该在启动主 ioloop 之前调用它.相同的连接对象在所有处理程序之间共享.
redis.connect is called only once. It is a blocking call, so it should be called before starting the main ioloop. The same connection object is shared between all the handlers.
您可以将其添加到您的应用程序设置中,例如
You could add it to your application settings like
settings = {
redis = redis_conn
}
app = tornado.web.Application([('/.*', Handler),],
**settings)
使用 tornadoredis
连接可以在处理程序中作为 self.settings['redis']
使用,也可以作为 BaseHandler 类的属性添加.您的请求处理程序子类化该类并访问该属性.
The connection can be used in handlers as self.settings['redis']
or it can be added as a property of the BaseHandler class. Your request handlers subclass that class and access the property.
class BaseHandler(tornado.web.RequestHandler):
@property
def redis():
return self.settings['redis']
为了与 redis 通信,使用了 tornado.web.asynchronous
和 tornado.gen.engine
装饰器
To communicate with redis, the tornado.web.asynchronous
and the tornado.gen.engine
decorators are used
class SomeHandler(BaseHandler):
@tornado.web.asynchronous
@tornado.gen.engine
def get(self):
foo = yield gen.Task(self.redis.get, 'foo')
self.render('sometemplate.html', {'foo': foo}
额外信息
可以在 github 存储库中找到更多示例和其他功能,例如连接池和管道.
More examples and other features like connection pooling and pipelines can be found at the github repo.
这篇关于在 Tornado 中处理 Redis 连接的正确方法是什么?(异步 - 发布/订阅)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!