Search code examples
python-3.xtornadopython-asyncioaiohttp

Using tornado with aiohttp (or other asyncio-based libraries)


I want to use tornado with asyncio libraries like aiohttp and native python 3.5 coroutines, and it seems to be supported in the latest tornado release (4.3). However when using it in tornado event loop, the request handler hangs indefinitely. When not using aiohttp (i.e. without the lines r = await aiohttp.get('http://google.com/') and text = await r.text() below), the request handler proceeds as normal.

My test code is as follows:

from tornado.ioloop import IOLoop
import tornado.web
import tornado.httpserver
import aiohttp

IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')


class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        r = await aiohttp.get('http://google.com/')
        text = await r.text()
        self.write("Hello, world, text is: {}".format(text))

if __name__ == "__main__":
    app = tornado.web.Application([
        (r"/", MainHandler),
    ])
    server = tornado.httpserver.HTTPServer(app)
    server.bind(8888, '127.0.0.1')
    server.start()
    IOLoop.current().start()

Solution

  • According to docs, you are doing it almost right. You have to create/init Tornado's ioloop with corresponding asyncio, since aiohttp is running on asyncio.

    from tornado.ioloop import IOLoop
    import tornado.web
    import tornado.httpserver
    import aiohttp
    from tornado.platform.asyncio import AsyncIOMainLoop
    import asyncio
    
    class MainHandler(tornado.web.RequestHandler):
        async def get(self):
            r = await aiohttp.get('http://google.com/')
            text = await r.text()
            self.write("Hello, world, text is: {}".format(text))
    
    if __name__ == "__main__":
        AsyncIOMainLoop().install()
        app = tornado.web.Application([
            (r"/", MainHandler),
        ])
        server = tornado.httpserver.HTTPServer(app)
        server.bind(1234, '127.0.0.1')
        server.start()
        asyncio.get_event_loop().run_forever()
    

    The reason why your code get stuck, is that asyncio's ioloop actually is not running, only the Tornado's one, so await is waiting indefinitely.