Подтвердить что ты не робот

Прекратить обработку маршрута колбы, если запрос прерван

У меня есть конечная точка REST флешки, которая выполняет некоторую интенсивную обработку процессора и занимает несколько секунд, чтобы вернуться. Часто эта конечная точка вызывается, а затем прерывается клиентом. В этих ситуациях я хотел бы отменить обработку. Как это сделать в колбе?

В node.js я бы сделал что-то вроде:

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

Я ожидал, что фляга будет иметь что-то подобное или синхронный метод (request.isClosed()), который я мог бы проверить в определенные моменты во время моей обработки и вернуть, если он закрыт, но я не могу найти его.

Я подумал о том, чтобы отправить что-то, чтобы проверить, что соединение все еще открыто, и перехватывает исключение, если оно не работает, но похоже, что флажок буферизует все выходы, поэтому исключение не генерируется до завершения обработки и пытается вернуть результат:

Установленное соединение было прервано программным обеспечением вашей хост-машины

Как я могу отменить свою обработку на полпути, если клиент прерывает их запрос?

4b9b3361

Ответ 1

Существует потенциально... хакерское решение вашей проблемы. Flask имеет возможность передавать содержимое обратно пользователю через генератор. Хакерная часть будет передавать потоковые данные в виде проверки, чтобы убедиться, что соединение все еще открыто, а затем, когда ваше содержимое закончено, генератор может создать фактическое изображение. Ваш генератор может проверить, завершена ли обработка, и вернуть None или "" или что-то еще, если оно не закончилось.

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

Я не знаю, какое исключение вы получите, если клиент закроет соединение, но я готов сделать ставку на его error: [Errno 32] Broken pipe

Ответ 2

Я просто пытался сделать то же самое в проекте, и я обнаружил, что с моим стеком uWSGI и nginx, когда потоковый ответ был прерван на стороне клиента, произошли следующие ошибки

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

и я мог бы просто использовать обычные старые try и except, как показано ниже

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

Это дало мне:

  • Мгновенная потоковая передача данных с использованием функции генератора фляшек
  • Никаких зомби-процессов при аннулированном соединении

Ответ 3

Насколько я знаю, вы не можете знать, было ли соединение закрыто клиентом во время выполнения, потому что сервер не тестирует, будет ли соединение открыто во время выполнения. Я знаю, что вы можете создать свой собственный request_handler в своем приложении Flask для обнаружения, если после обработки запроса соединение было "отброшено".

Например:

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) 

Возможно, вам нужно немного поработать, и по мере создания вашего пользовательского request_handler при поступлении запроса вы можете создать поток в __init__, который проверяет состояние соединения каждую секунду и когда он обнаруживает, что соединение (проверить эту тему), то прекратите обработку изображения. Но я думаю, что это немного сложно: (.