python http rest flask wsgi

python - Detener el procesamiento de la ruta del matraz si se canceló la solicitud



subplot python (3)

Tengo un punto final REST en el matraz que realiza un procesamiento de imagen intensivo de CPU y tarda unos segundos en regresar. A menudo, este punto final recibe un llamado, luego es cancelado por el cliente. En estas situaciones, me gustaría cancelar el procesamiento. ¿Cómo puedo hacer esto en el matraz?

En node.js, haría algo como:

req.on(''close'', function(){ //some handler });

Esperaba que el matraz tuviera algo similar, o un método sincrónico (request.isClosed ()) que pudiera verificar en ciertos puntos durante mi procesamiento y regresar si está cerrado, pero no puedo encontrar uno.

Pensé en enviar algo para probar que la conexión todavía está abierta, y atrapar la excepción si falla, pero parece que Flask almacena en búfer todos los resultados, por lo que la excepción no se lanza hasta que el procesamiento finalice e intente devolver el resultado:

Una conexión establecida fue abortada por el software en su máquina host

¿Cómo puedo cancelar mi procesamiento a la mitad si el cliente aborta su solicitud?


Existe una solución potencialmente ... hacky para su problema. streaming . La parte hacky estaría transmitiendo datos en blanco como una verificación para ver si la conexión aún está abierta y luego, cuando el contenido haya terminado, el generador podría generar la imagen real. Su generador podría verificar para ver si el procesamiento está hecho y devolver None o "" o lo que sea si no está terminado.

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'')

No sé qué excepción obtendrás si el cliente cierra la conexión, pero estoy dispuesto a apostar su error: [Errno 32] Broken pipe


Por lo que sé, no se puede saber si el cliente ha cerrado una conexión durante la ejecución porque el servidor no está probando si la conexión está abierta durante la ejecución. Sé que puede crear su request_handler personalizado en su aplicación Flask para detectar si después de procesar la solicitud, la conexión se "cayó".

Por ejemplo:

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)

Tal vez quieras investigar un poco más y como tu request_handler personalizado se crea cuando llega una solicitud, puedes crear un hilo en __init__ que verifica el estado de la conexión cada segundo y cuando detecta que la conexión está cerrada ( consulta este hilo ) luego detenga el procesamiento de la imagen. Pero creo que esto es un poco complicado :(.


Solo estaba intentando hacer lo mismo en un proyecto y encontré que con mi pila de uWSGI y nginx, cuando se interrumpía una respuesta de transmisión por el lado del cliente, ocurrían los siguientes errores

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

y podría usar un viejo try normal y except como a continuación

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

Esto me dio:

  1. Transmisión instantánea de datos utilizando la funcionalidad del generador de Flask
  2. No hay procesos zombie en la conexión cancelada