如果请求中止,则停止处理Flask路由

时间:2013-08-29 12:32:19

标签: python http rest flask wsgi

我有一个烧瓶REST端点,它执行一些cpu密集型图像处理,并需要几秒钟才能返回。通常,此端点被调用,然后由客户端中止。在这些情况下,我想取消处理。我怎么能在烧瓶中做到这一点?

在node.js中,我会做类似的事情:

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

我期待烧瓶有类似的东西,或同步方法(request.isClosed()),我可以在处理过程中检查某些点,如果它关闭则返回,但我找不到。

我考虑发送一些东西来测试连接是否仍然打开,如果失败则捕获异常,但似乎Flask缓冲所有输出,因此在处理完成并尝试返回结果之前不会抛出异常:

  

已建立的连接已被主机中的软件中止

如果客户端中止了他们的请求,我怎样才能取消处理中途?

3 个答案:

答案 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

我可以使用常规旧tryexcept,如下所示

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

这给了我:

  1. 使用Flask的生成器功能即时流式传输数据
  2. 取消连接时没有僵尸进程

答案 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),然后停止图像处理。但我认为这有点复杂:(。