36

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

在 node.js 中,我会执行以下操作:

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

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

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

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

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

4

3 回答 3

20

您的问题有一个潜在的... hacky 解决方案。Flask 能够通过生成器将内容流回给用户。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

于 2013-09-06T22:09:57.277 回答
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. 取消连接时没有僵尸进程
于 2014-01-14T05:03:23.877 回答
0

据我所知,您不知道在执行期间客户端是否关闭了连接,因为服务器没有测试连接在执行期间是否打开。我知道您可以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__每秒检查连接的状态,当它检测到连接已关闭(检查此线程)然后停止图像处理。但我认为这有点复杂:(。

于 2013-09-03T18:06:25.600 回答