loretoparisi
loretoparisi

Reputation: 16301

Port Tornado application to gunicorn

I'm running a Python api server with a Tornado application. My Tornado app uses tornado.web and is defined like

from tornado import web

def application():

    handlers = [
        # apis
        (r'/api/1', th.APIHandler1),
        (r'/api/2', th.APIHandler2)
    ]

    settings = dict()
    return web.Application(handlers, **settings) 

So it runs in the IOLoop like

app = application()
app.listen(int(PORT))
ioloop.IOLoop.instance().start()

So it is not a WSGI application. The handlers will typically be decorated with the @tornado.web.asynchronous pattern, and for cpu-intensive task with the @tornado.gen.coroutine pattern or in some specific case for long duration tasks with the @tornado.concurrent.run_on_executor decorator to run as a thread in a thread pool. In this specific case I'm using a bounded thread pool executor like:

class MyHandler2(tornado.web.RequestHandler):
    executor = BoundedThreadPoolExecutor(max_workers=5)
    @tornado.concurrent.run_on_executor
    def get(self, *args):

I want to port this to gunicorn to take advantage of pre-fork workers approach. A possible solution I have investigated is the gunicorn multi app pattern that should look like:

from routes import Mapper
from test import app as apiHandler1
from test import app as apiHandler2


class Application(object):
    def __init__(self):
        self.map = Mapper()
        self.map.connect('app1', '/api/1', app=apiHandler1)
        self.map.connect('app2', '/api/2', app=apiHandler2)

    def __call__(self, environ, start_response):
        match = self.map.routematch(environ=environ)
        if not match:
            return self.error404(environ, start_response)
        return match[0]['app'](environ, start_response)

app = Application()

There is no specific docs about porting a Tornado asynchronous app to gunicorn wsgi app, so my question is if this approach can be the correct one.

Upvotes: 0

Views: 520

Answers (1)

Ben Darnell
Ben Darnell

Reputation: 22154

Tornado is not a WSGI-based framework, so it cannot be used in a WSGI application server (it was possible to run a subset of Tornado applications in a WSGI-compatible mode in older versions of Tornado, but this was removed in Tornado 6.0). Gunicorn has a Tornado-specific worker_class that must be used instead.

Upvotes: 1

Related Questions