web-dev-qa-db-ja.com

処理を停止Flaskリクエストが中止された場合のルート

私はflask RESTエンドポイントを使用しており、CPUを集中的に使用する画像処理を実行し、返されるまでに数秒かかります。多くの場合、このエンドポイントは呼び出され、次にクライアントこのような状況で処理をキャンセルしたいのですが、フラスコでこれを行うにはどうすればよいですか?

Node.jsでは、次のようにします。

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

flaskが似たようなもの、または同期メソッド(request.isClosed())を期待していたが、処理中に特定のポイントでチェックし、閉じている場合は返すことができるが、できない見つけて。

接続がまだ開いていることをテストするために何かを送信し、それが失敗した場合に例外をキャッチすることを考えましたが、Flaskはすべての出力をバッファリングするため、処理が完了するまで例外はスローされません。結果を返そうとします:

確立された接続は、ホストマシンのソフトウェアによって中止されました

クライアントがリクエストを中止した場合、どのように処理を途中でキャンセルできますか?

32
Crashthatch

潜在的に...あなたの問題に対するハッキーな解決策があります。 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を賭けます

17
AlexLordThorsen

私はプロジェクトでこれと同じことをやろうとしたところ、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. キャンセルされた接続にゾンビプロセスはありません
1
Emory Petermann