El servidor de tornado arroja un error La secuencia está cerrada

Estoy tratando de implementar una página web de chat / echo muy básica.

Cuando el cliente visita / notifica: 8000 se carga un sitio simple, en el lado del cliente se inicia una solicitud para establecer una escucha, en el back-end, el recuento de la nube se actualiza y se envía a todos los clientes existentes.

Cada vez que el usuario ingresa algo en un cuadro de texto, se hace un POST al back-end y todos los demás clientes reciben una actualización con ese texto.

Aquí está la plantilla de front-end

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
</head>
<body>
    <p>session: <span id="session">{{ session }}</span><br/>
    client count: <span id="clientCount">{{ clientCount }}</span><br/>
    <span id="welcome">...registering with notify...</span></p>

    <div style="width: 600px; height: 100px; border: 1px solid black; overflow:auto; padding: 4px;" id="chatText">

    </div>

    <div>
    <span>enter text below:</span><br />
    <input type="text" id="textInput"></textarea>
    <div>

<script>

$(document).ready(function() {
    document.session = $('#session').html();
    setTimeout(initializeListener, 100);


    $('#textInput').keypress(function(e) {
    //    e.preventDefault(); 
        if(e.keyCode == 13 && !e.shiftKey) {
            var text = $('#textInput').val();
            submitChatText(text);
            return false;
        }
    });
});

var logon = '1';

function initializeListener() {
    console.log('initializeListener() called');
    jQuery.getJSON('//localhost/notify/listen', {logon: logon, session: document.session},
        function(data, status, xhr) {
            console.log('initializeListener() returned');
            if ('clientCount' in data) {
                $('#clientCount').html(data['clientCount']);
            }
            if ('chatText' in data) {
                text = $('#chatText').html()
                $('#chatText').html(data['chatText'] + "<br />\n" + text);
            }
            if (logon == '1') {
                $('#welcome').html('registered listener with notify!');
                logon = '0';
            }
            setTimeout(initializeListener, 0);
        })
        .error(function(XMLHttpRequest, textStatus, errorThrown) {
            console.log('error: '+textStatus+' ('+errorThrown+')');
            setTimeout(initializeListener, 100);
        });
}

function submitChatText(text) {
    console.log('submitChatText called with text: '+text)
    jQuery.ajax({
        url: '//localhost/notify/send',
        type: 'POST',
        data: {
            session: document.session,
            text: ''+text
        },
        dataType: 'json',
        //beforeSend: function(xhr, settings) {
        //    $(event.target).attr('disabled', 'disabled');
        //},
        success: function(data, status, xhr) {
            console.log('sent text message')
            $("#textInput").val('');
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            console.log('error: '+textStatus+' ('+errorThrown+')');
        }
    });


}

</script>
</body>
</html>

Aquí está el código del servidor:

import tornado.ioloop
import tornado.web
import tornado.options
from uuid import uuid4
import json

class Client(object):
    callbacks = {}
    chat_text = ''

    def register(self, callback, session, logon=False):
        self.callbacks[session] = callback
        if logon == '1':
            self.notifyCallbacks()

    def notifyCallbacks(self):
        result = {}
        result['clientCount'] = self.getClientCount()
        if self.chat_text:
            result['chatText'] = self.chat_text

        for session, callback in self.callbacks.iteritems():
            callback(result)

        self.callbacks = {}

    def sendText(self, session, text):
        self.chat_text = text
        self.notifyCallbacks()
        self.chat_text = ''

    def getClientCount(self):
        return len(self.callbacks)

class Application(tornado.web.Application):
    def __init__(self):
        self.client = Client()
        handlers = [
            (r"/notify", MainHandler),
            (r"/notify/listen", ListenHandler),
            (r"/notify/send", SendHandler)
        ]
        settings = dict(
            cookie_secret="43oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
            template_path="templates/notify",
        )
        tornado.web.Application.__init__(self, handlers, **settings)

class ListenHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        logon = self.get_argument('logon')
        session = self.get_argument('session')
        self.application.client.register(self.on_message, session, logon)

    def on_message(self, result):
        json_result = json.dumps(result)
        self.write(json_result)
        self.finish()

class SendHandler(tornado.web.RequestHandler):
    def post(self):
        text = self.get_argument('text')
        session = self.get_argument('session')
        self.application.client.sendText(session, text)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        session = uuid4()
        client_count= self.application.client.getClientCount()
        self.render("testpage.html", session=session, clientCount=client_count)


if __name__ == '__main__':
    application = Application()
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

Luego, a veces, el servidor genera errores cuando cierro una pestaña e intento transmitir desde otra. El error es así:

    ERROR:root:Uncaught exception POST /notify/send (127.0.0.1)
HTTPRequest(protocol='http', host='localhost', method='POST', uri='/notify/send', version='HTTP/1.1', remote_ip='127.0.0.1', body='session=e5608630-e2c7-4e1a-baa7-0d74bc0ec9fc&text=swff', headers={'Origin': 'http://localhost', 'Content-Length': '54', 'Accept-Language': 'en-US,en;q=0.8', 'Accept-Encoding': 'gzip,deflate,sdch', 'X-Forwarded-For': '127.0.0.1', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Host': 'localhost', 'X-Requested-With': 'XMLHttpRequest', 'X-Real-Ip': '127.0.0.1', 'Referer': 'http://localhost/notify', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'})
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/tornado/web.py", line 1021, in _execute
    getattr(self, self.request.method.lower())(*args, **kwargs)
  File "test.py", line 66, in post
    self.application.client.sendText(session, text)
  File "test.py", line 30, in sendText
    self.notifyCallbacks()
  File "test.py", line 24, in notifyCallbacks
    callback(result)
  File "test.py", line 60, in on_message
    self.finish()
  File "/usr/lib/python2.7/site-packages/tornado/web.py", line 701, in finish
    self.request.finish()
  File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 433, in finish
    self.connection.finish()
  File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 187, in finish
    self._finish_request()
  File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 223, in _finish_request
    self.stream.read_until(b("\r\n\r\n"), self._header_callback)
  File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 153, in read_until
    self._try_inline_read()
  File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 381, in _try_inline_read
    self._check_closed()
  File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 564, in _check_closed
    raise IOError("Stream is closed")
IOError: Stream is closed

Obviamente, esto se debe a que la pestaña estaba cerrada, por lo que el cliente ya no está escuchando, pero eso debería ser algo normal, ¿cómo puedo manejar esa situación con más gracia?

Lo único que pude encontrar sobre este error, fue otra publicación de stackoverflow, la sugerencia fue verificar si la conexión se completó antes de llamar al método finish ():

if not self._finished:
    self.finish()

Sin embargo, cuando intenté eso, no parecía ayudar, seguía teniendo el mismo error, O obtendría otro errorAssertionError: Solicitud cerrada que no pude encontrar ninguna ayuda en

Respuestas a la pregunta(1)

Su respuesta a la pregunta