用Tornado 构建一个 Comet 应用

说明1:使用此decorator即可以把get方法non-blocking化

说明2:non-blocking化的请求必须调用self.finish()完成请求

说明3:如果需要sleep等待,应该使用Tornado的IOLoop的add_timeout方法。使用其他休眠方法如time.sleep会block住当前线程,而Tornado是一个单线程Server,会导致其他请求无法执行的问题。

此时执行comet.py,一个non-blocking的server端已经搭建成功。

要注意的问题是,如果不加超时机制,服务端会不断执行,即使客户端已经断开。因此还需自己实现超时机制。

#!/usr/bin/env python
import tornado.httpserver
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous #说明1
    def get(self):
        some_async_func(callback=self.wait)

    def wait(self, result):
        if result:
            self.write(result)
            self.finish() #说明2
        else:
            tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 0.5,lambda: some_async_func(callback=self.wait))
            #说明3

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8999)
    tornado.ioloop.IOLoop.instance().start()

在Nginx 配置里添加超时机制

upstream frontends {
    server 127.0.0.1:8999;
}

server {
    listen 8888;
    location / {
        proxy_read_timeout 1800;
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://frontends;
    }
}

需要特别指出的是,要根据上述应用的超时机制,设置proxy_read_timeout,proxy_read_timeout必须大于应用的超时。否则将会有504请求返回。 它说明由nginx向tornado请求了长连接以后,等到1800秒之后,如果tornado还没有返回。则nginx返回504 Gateway Timeout给客户端浏览器。

Relative Articles