Stop processing Flask route if request aborted

后端 未结 3 520
予麋鹿
予麋鹿 2020-12-13 06:48

I have a flask REST endpoint that does some cpu-intensive image processing and takes a few seconds to return. Often, this endpoint gets called, then aborted by the client. I

相关标签:
3条回答
  • 2020-12-13 07:12

    I was just attempting to do this same thing in a project and I found that with my stack of uWSGI and nginx that when a streaming response was interrupted on the client's end that the following errors occurred

    SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request
    uwsgi_response_write_body_do(): Broken pipe [core/writer.c line 404] during GET
    IOError: write error
    

    and I could just use a regular old try and except like below

        try:
            for chunk in iter(process.stdout.readline, ''):
                yield chunk
            process.wait()
        except:
            app.logger.debug('client disconnected, killing process')
            process.terminate()
            process.wait()
    

    This gave me:

    1. Instant streaming of data using Flask's generator functionality
    2. No zombie processes on cancelled connection
    0 讨论(0)
  • 2020-12-13 07:16

    There is a potentially... hacky solution to your problem. Flask has the ability to stream content back to the user via a generator. The hacky part would be streaming blank data as a check to see if the connection is still open and then when your content is finished the generator could produce the actual image. Your generator could check to see if processing is done and return None or "" or whatever if it's not finished.

    from flask import Response
    
    @app.route('/image')
    def generate_large_image():
        def generate():
            while True:
                if not processing_finished():
                    yield ""
                else:
                    yield get_image()
        return Response(generate(), mimetype='image/jpeg')
    

    I don't know what exception you'll get if the client closes the connection but I'm willing to bet its error: [Errno 32] Broken pipe

    0 讨论(0)
  • 2020-12-13 07:25

    As far as I know you can't know if a connection was closed by the client during the execution because the server is not testing if the connection is open during the execution. I know that you can create your custom request_handler in your Flask application for detecting if after the request is processed the connection was "dropped".

    For example:

    from flask import Flask
    from time import sleep
    from werkzeug.serving import WSGIRequestHandler
    
    
    app = Flask(__name__)
    
    
    class CustomRequestHandler(WSGIRequestHandler):
    
        def connection_dropped(self, error, environ=None):
            print 'dropped, but it is called at the end of the execution :('
    
    
    @app.route("/")
    def hello():
        for i in xrange(3):
            print i
            sleep(1)
        return "Hello World!"
    
    if __name__ == "__main__":
        app.run(debug=True, request_handler=CustomRequestHandler) 
    

    Maybe you want to investigate a bit more and as your custom request_handler is created when a request comes you can create a thread in the __init__ that checks the status of the connection every second and when it detects that the connection is closed ( check this thread ) then stop the image processing. But I think this is a bit complicated :(.

    0 讨论(0)
提交回复
热议问题