lundi 23 octobre 2017

Tornado server caused Django unable to handle concurrent requests

I wrote a Django website that handles concurrent database requests and subprocess calls perfectly fine, if I just run "python manage.py runserver"

This is my model

class MyModel:
    ...
    def foo(self):
        args = [......]
        pipe = subprocess.Popen(args, stdout=subproccess.PIPE, stderr=subprocess.PIPE)

In my view:

def call_foo(request):
    my_model = MyModel()
    my_model.foo()

However, after I wrap it using Tornado server, it's no longer able to handle concurrent request. When I click my website where it sends async get request to this call_foo() function, it seems like my app is not able to handle other requests. For example, if I open the home page url, it keeps waiting and won't display until the above subprocess call in foo() has finished.

If I do not use Tornado, everything works fine.

Below is my code to start the tornado server. Is there anything that I did wrong?

MAX_WAIT_SECONDS_BEFORE_SHUTDOWN = 5

def sig_handler(sig, frame):
    logging.warning('Caught signal: %s', sig)
    tornado.ioloop.IOLoop.instance().add_callback(force_shutdown)

def force_shutdown():
    logging.info("Stopping tornado server")
    server.stop()
    logging.info('Will shutdown in %s seconds ...', MAX_WAIT_SECONDS_BEFORE_SHUTDOWN)
    io_loop = tornado.ioloop.IOLoop.instance()
    deadline = time.time() + MAX_WAIT_SECONDS_BEFORE_SHUTDOWN

    def stop_loop():
        now = time.time()
        if now < deadline and (io_loop._callbacks or io_loop._timeouts):
            io_loop.add_timeout(now + 1, stop_loop)
        else:
            io_loop.stop()
            logging.info('Force Shutdown')
    stop_loop()

def main():
    parse_command_line()
    logging.info("starting tornado web server")
    os.environ['DJANGO_SETTINGS_MODULE'] = 'mydjango.settings'
    django.setup()
    wsgi_app = tornado.wsgi.WSGIContainer(django.core.handlers.wsgi.WSGIHandler())
    tornado_app = tornado.web.Application([
        (r'/(favicon\.ico)', tornado.web.StaticFileHandler, {'path': "static"}),
        (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': "static"}),
        ('.*', tornado.web.FallbackHandler, dict(fallback=wsgi_app)),
      ])
    global server
    server = tornado.httpserver.HTTPServer(tornado_app)
    server.listen(options.port)

    signal.signal(signal.SIGTERM, sig_handler)
    signal.signal(signal.SIGINT, sig_handler)

    tornado.ioloop.IOLoop.instance().start()

    logging.info("Exit...")

if __name__ == '__main__':
    main()




Aucun commentaire:

Enregistrer un commentaire