在 Tornado 中处理 Redis 连接的正确方法是什么?(异步 - 发布/订阅) [英] What is the proper way to handle Redis connection in Tornado ? (Async - Pub/Sub)

查看:106
本文介绍了在 Tornado 中处理 Redis 连接的正确方法是什么?(异步 - 发布/订阅)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 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.asynchronoustornado.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆