Tornado long polling requests
Asked Answered
C

1

1

Below is the most simple example of my issue:

When a request is made it will print Request via GET <__main__.MainHandler object at 0x104041e10> and then the request will remain open. Good! However, when you make another request it does not call the MainHandler.get method until the first connection has finished.

How can I get multiple requests into the get method while having them remain long-polling. I'm passing arguments with each request that will get different results from a pub/sub via redis. Issue is that I only get one connection in at a time. Whats wrong? And why is this blocking other requests?

import tornado.ioloop
import tornado.web
import os


class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        print 'Request via GET', self


if __name__ == '__main__':
    application = tornado.web.Application([
        (r"/", MainHandler)])

    try:
        application.listen(int(os.environ.get('PORT', 5000)))
        tornado.ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        tornado.ioloop.IOLoop.instance().stop()

Diagram Left: As described in issue above. The requests are not handled in the fashion requested in right diagram. Diagram on the right I need the requests (a-d) to be handled by the RequestHandler and then wait for the pub/sub to announce their data.

       a  b   c   d
       +  +   +   +                        ++          a    b   c   d
       |  |   |   |                        ||          +    +   +   +
       |  |   |   |                        ||          |    |   |   |
       |  |   |   |                        ||          |    |   |   |
       |  |   |   |                        ||          |    |   |   |
       |  v   v   v                        ||          |    |   |   |
   +---|-----------------------------+     ||    +-----|----|---|---|------------------+
   |   |                             |     ||    |     |    |   |   |                  |
   |   +               RequestHandler|     ||    |     +    +   +   +     RequestHan.  |
   |   |                             |     ||    |     |    |   |   |                  |
   +---|-----------------------------+     ||    +-----|----|---|---|------------------+
   +---|-----------------------------+     ||    +-----|----|---|---|------------------+
   |   |                             |     ||    |     |    |   |   |                  |
   |   +                Sub/Pub Que  |     ||    |     v    +   v   v         Que      |
   |   |                             |     ||    |          |                          |
   +---|-----------------------------+     ||    +----------|--------------------------+
   +---|-----------------------------+     ||    +----------|--------------------------+
       |                                   ||               |
       |                 Finished          ||               |               Finished
       v                                   ||               v
                                           ||
                                           ||
                                           ||
                                           ||
                                           ||
                                           ||
                                           ||
                                           ++

If this is accomplishable with another programming language please let me know.

Thank you for your help!

Collins answered 16/6, 2013 at 17:10 Comment(0)
Q
2

From http://www.tornadoweb.org/en/stable/web.html#tornado.web.asynchronous:

tornado.web.asynchronous(method)

...

If this decorator is given, the response is not finished when the method returns. It is up to the request handler to call self.finish() to finish the HTTP request. Without this decorator, the request is automatically finished when the get() or post() method returns.

You have to finish get method explicitly:

import tornado.ioloop
import tornado.web
import tornado.options

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        print 'Request via GET', self
        self.finish()


if __name__ == '__main__':
    application = tornado.web.Application([
        (r"/", MainHandler)])

    try:
        application.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        tornado.ioloop.IOLoop.instance().stop()
Quandary answered 16/6, 2013 at 19:34 Comment(2)
I appreciate your response. However, I'm looking for a way to perform a long polling request. Not just close the connection but keep it alive until I have data for it. And the data will be fed from redis sub/pub and will be different for every connected client.Collins
@StevePeak Did you find any solution to this because I'm trying to do the same in tornado. I need to create a long polling endpoint in tornado and return data when I get something from redis. I'm very new to tornado and async programming in general.Pepsin

© 2022 - 2024 — McMap. All rights reserved.