Why asynchronous function in tornado is blocking?

Why incoming request are not being processed while another request is in the "waiting" state?

If you look at the code below, function "get" has a tornado task which is executed with "yield" keyword, which would mean "wait for a callback to be executed". In my code, the callback is never executed. If you run request second time, while first is on hold, the second request is not processed. If you run any other requests, they are being processed just fine.

So, my actions: 1. Start application 2. GET localhost:8080/ - Application is printing output "incoming call" 3. GET localhost:8080/anotherrequest - Application is printing output "another request" 4. GET localhost:8080/ - Application is not printing any output while I'm expecting it to print "incoming call". Why?

So, why this piece of code gets blocking? Code sample is attached.

I was using tornado 2.1 and python 2.7 to run this sample.

Thank you

import tornado
import tornado.web
from tornado import gen

class AnotherHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        print 'another request'
        self.finish()

class MainHandler(tornado.web.RequestHandler):
    def printStuff(*args, **kwargs):
        print 'incoming call'

    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        result = yield tornado.gen.Task(self.printStuff); 

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

if __name__ == "__main__":
    application.listen(8080)
    tornado.ioloop.IOLoop.instance().start()

Answers


Each new request to "localhost:8080/" will, in fact, cause your application to print "incoming call." However, requests to "localhost:8080/" will never finish. In order for the yield statement to be used, printStuff has to accept a callback and execute it. Also, an asynchronous get function must call self.finish:

class MainHandler(tornado.web.RequestHandler):
    def printStuff(self, callback):
        print 'incoming call'
        callback()

    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        result = yield tornado.gen.Task(self.printStuff)
        self.finish()

It's easier to use Tornado's modern "coroutine" interface instead of gen.Task and gen.engine:

class MainHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def printStuff(self):
        print 'incoming call'

    @gen.coroutine
    def get(self):
        result = yield self.printStuff()
        self.finish()

Found the problem, it's actually happening when requests are made from the browser. With "curl" everything works as expected. Sorry for inconvenience.


Need Your Help

Most efficient way of creating tree from adjacency list

c# algorithm adjacency-list

I have an adjacency list of objects (rows loaded from SQL database with the key and it's parent key) that I need to use to build an unordered tree. It's guaranteed to not have cycles.

Return parent and children in single entity framework query WITHOUT returning IQueryable or IEnumerable?

c# entity-framework linq automapper

We have a rule to not expose IQueryable<T> or IEnumerable<T> outside of the service layer so downstream code can't modify the query going to the database. This means that the types we r...