Search code examples
pythonweb-servicestornado

How can I detect when the client drops while receiving a response


I have a simple tornado app like this that lets the user download a large file. I need to be able to detect when the client drops and raise an exception.

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        print "hello"

        self.write("A"*10000000)
        self.flush()
        self.finish()
        print "world"

If I curl this method and ctrl-C while it is downloading the As, the print "world" statement is still executed. I would like to be able to detect when the curl command is closed and raise an exception instead of continuing to finish my get() method.

What is the best way to do this in Tornado?


Solution

  • First, you have to make your handler asynchronous. Second, you can override on_connection_close to get alerted when the connection is aborted.

    import tornado.ioloop
    import tornado.web
    from tornado import gen
    
    class MainHandler(tornado.web.RequestHandler):
        def initialize(self):
            self.aborted = False
    
        @gen.coroutine
        def get(self):
            print "hello"
    
            self.write("A"*10000000)
            yield gen.Task(self.flush)  # This is asynchronous, so on_connection_close can run while this flushes.
            self.finish()
            if not self.aborted:
                print "world"
    
        def on_connection_close(self):
            self.aborted = True
            print("aborted")
    
    
    application = tornado.web.Application([
        (r"/test", MainHandler),
    ])
    application.listen(8888)
    
    tornado.ioloop.IOLoop.instance().start()
    

    Note that this isn't guaranteed to work if the only asynchronous call in your handler is to self.flush: Unless you're writing a lot of data, tornado may flush all the data to the buffer prior to the client-side aborting the connection. It works consistently with this example code on my machine, though.