Search code examples
chatreal-timetornado

my Tornado chat is losing messages


i am losing messages in my tornado chat and i do not known how to detect when the message wasn't sent and to send the message again

there is any way to detect when the conexion get lost? and when the conexión restart send the message

this is my code

def get(self):
    try:
        json.dumps(MessageMixin.cache)
    except KeyError:
        raise tornado.web.HTTPError(404)




class MessageMixin(object):
    waiters = {}
    cache = {}
    cache_size = 200

    def wait_for_messages(self,cursor=None):
        t = self.section_slug           
        waiters = self.waiters.setdefault(t, [])
        result_future = Future()

        waiters.append(result_future)
        return result_future

    def cancel_wait(self, future):
        t = self.section_slug
        waiters = self.waiters.setdefault(t, [])
        waiters.remove(future)
        # Set an empty result to unblock any coroutines waiting.
        future.set_result([])

    def new_messages(self, message):
        t = self.section_slug
        #cache = self.cache.setdefault(t, [])
        #print t
        #print self.waiters.setdefault(t, [])
        waiters = self.waiters.setdefault(t, [])        
        for future in waiters:
            try:
                if message is not None:
                    future.set_result(message)
            except Exception:

                logging.error("Error in waiter callback", exc_info=True)
        waiters = []
        #self.cache.extend(message)
        #if len(self.cache) > self.cache_size:
            #self.cache = self.cache[-self.cache_size:]


class MessageNewHandler(MainHandler, MessageMixin):
    def post(self, section_slug):
        self.section_slug = section_slug
        post = self.get_argument("html")
        idThread = self.get_argument("idThread")
        isOpPost = self.get_argument("isOpPost")
        arg_not = self.get_argument("arg")
        type_not = self.get_argument("type")
        redirect_to = self.get_argument("next", None)
        message= {"posts": [post],"idThread": idThread,"isOpPost": isOpPost, 
                    "type": type_not,"arg_not": arg_not}
        if redirect_to:
            self.redirect(redirect_to)
        else:
            self.write(post)
        self.new_messages(message)


class MessageUpdatesHandler(MainHandler, MessageMixin):
    @gen.coroutine
    def post(self, section_slug):
        self.section_slug = section_slug
        try:
            self.future = self.wait_for_messages(cursor=self.get_argument("cursor", None))
            data = yield self.future
            if self.request.connection.stream.closed():             
                return          
            self.write(data)
        except Exception:

            raise tornado.web.HTTPError(404)

    def on_connection_close(self):

        self.cancel_wait(self.future)   


class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/api/1\.0/stream/(\w+)", MessageUpdatesHandler),
            (r"/api/1\.0/streamp/(\w+)", MessageNewHandler)

        ]
        tornado.web.Application.__init__(self, handlers)


def main():
    tornado.options.parse_command_line()
    app = Application()
    port = int(os.environ.get("PORT", 5000))
    app.listen(port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

Solution

  • In the original chatdemo, this is what the cursor parameter to wait_for_messages is for: the browser tells you the last message it got, so you can send it every message since then. You need to buffer messages and potentially re-send them in wait_for_messages. The code you've quoted here will only send messages to those clients that are connected at the time the message came in (and remember that in long-polling, sending a message puts the client out of the "waiting" state for the duration of the network round-trip, so even when things are working normally clients will constantly enter and leave the waiting state)