Прекратить обработку маршрута колбы, если запрос прерван
У меня есть конечная точка REST флешки, которая выполняет некоторую интенсивную обработку процессора и занимает несколько секунд, чтобы вернуться. Часто эта конечная точка вызывается, а затем прерывается клиентом. В этих ситуациях я хотел бы отменить обработку. Как это сделать в колбе?
В node.js я бы сделал что-то вроде:
req.on('close', function(){
//some handler
});
Я ожидал, что фляга будет иметь что-то подобное или синхронный метод (request.isClosed()), который я мог бы проверить в определенные моменты во время моей обработки и вернуть, если он закрыт, но я не могу найти его.
Я подумал о том, чтобы отправить что-то, чтобы проверить, что соединение все еще открыто, и перехватывает исключение, если оно не работает, но похоже, что флажок буферизует все выходы, поэтому исключение не генерируется до завершения обработки и пытается вернуть результат:
Установленное соединение было прервано программным обеспечением вашей хост-машины
Как я могу отменить свою обработку на полпути, если клиент прерывает их запрос?
Ответы
Ответ 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__
, который проверяет состояние соединения каждую секунду и когда он обнаруживает, что соединение (проверить эту тему), то прекратите обработку изображения. Но я думаю, что это немного сложно: (.