我有一个烧瓶REST端点,它执行一些cpu密集型图像处理,并需要几秒钟才能返回。通常,此端点被调用,然后由客户端中止。在这些情况下,我想取消处理。我怎么能在烧瓶中做到这一点?
在node.js中,我会做类似的事情:
req.on('close', function(){
//some handler
});
我期待烧瓶有类似的东西,或同步方法(request.isClosed()),我可以在处理过程中检查某些点,如果它关闭则返回,但我找不到。
我考虑发送一些东西来测试连接是否仍然打开,如果失败则捕获异常,但似乎Flask缓冲所有输出,因此在处理完成并尝试返回结果之前不会抛出异常:
已建立的连接已被主机中的软件中止
如果客户端中止了他们的请求,我怎样才能取消处理中途?
答案 0 :(得分:17)
你的问题有一个潜在的...... hacky解决方案。 Flask has the ability to stream content back to the user via a generator。 hacky部分将流式传输空白数据作为检查以确定连接是否仍然打开,然后当您的内容完成时,生成器可以生成实际图像。您的生成器可以检查是否已完成处理并返回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
答案 1 :(得分:1)
我只是试图在一个项目中做同样的事情,我发现在我的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()
这给了我:
答案 2 :(得分:-1)
据我所知,您无法知道客户端在执行期间是否关闭了连接,因为如果在执行期间连接处于打开状态,服务器不会测试。我知道您可以在Flask应用程序中创建自定义request_handler
,以检测在处理请求后是否已“删除”连接。
例如:
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__
中创建一个线程,每隔一秒检查一次连接的状态检测到连接已关闭(check this thread),然后停止图像处理。但我认为这有点复杂:(。