Can a Tornado WebSocketHandler receive messages asynchronously?
Question: On the python side, I've created a `WebSocketHandler`.

    
    
    from tornado import gen
    from tornado.escape import json_decode
    from tornado.websocket import WebSocketHandler
    
    class Echo(WebSocketHandler):
        ...
        @gen.coroutine
        def on_message(self, message):
            message = json_decode(message)
            response = yield self.do_echo(message)
            self.write_message(response)
    
        @gen.coroutine
        def do_echo(self, message):
            # emulate long, blocking call
            sleep(randint(0, 5))
            raise gen.Return(message)
    

On the javascript side, I start multiple clients (different browsers) at the
same time with:

    
    
    var ws = new WebSocket('ws://localhost:5000/echo');
    
    ws.onmessage = function (evt) {
        console.log(JSON.parse(evt.data));
    }
    
    for (var i = 0; i < 10; i++) {
        var msg = {
            messageid: i,
            payload: 'An echo message.'
        };
        ws.send(JSON.stringify(msg));
    }
    

All clients, as expected, finish at roughly the same time. However, each
client's received messages are logged in the exact order (`messageid`) that
they were sent as if the `WebSocketHandler` is queuing messages. Python logs
on the server side reflect this as well.

So then, my questions are:

  * Why is each message read and returned in the order that it was sent?
  * Is it possible to circumvent this queuing behavior? How?
  * Am I completely missing something embarrassingly basic?

Note that this is not the real code but a reasonable facsimile.


Answer: You must never run "long, blocking calls" on the IOLoop thread, because that
blocks everything else. That `sleep` call (or whatever it's standing in for),
must either be rewritten to be asynchronous or handed off to another thread
(which is fairly easy with `concurrent.futures.ThreadPoolExecutor`). See
<http://www.tornadoweb.org/en/stable/faq.html#why-isn-t-this-example-with-
time-sleep-running-in-parallel> for more on this.

