2013-08-29 13 views
23

CPUの集中処理を行うフラスコのRESTエンドポイントがあり、戻すには数秒かかります。多くの場合、このエンドポイントが呼び出され、クライアントによってアボートされます。このような状況では、処理をキャンセルしたいと思います。どのように私はフラスコでこれを行うことができますか? Node.jsので処理を中止する要求が中止された場合はフラスコのルート

、私のようなものだろう:私は中に特定の時点で確認することができると似たような、または同期メソッド(request.isClosedを())を持つようにフラスコを期待していた

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

を私の処理とそれが閉じている場合は戻ってきますが、見つけられません。

私は、接続がまだ開いていることをテストするために何かを送信し、失敗した場合に例外をキャッチすることを考えましたが、処理が完了して結果を返すまで例外がスローされないように:

An established connection was aborted by the software in your host machine

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

+0

あなたが「クライアントによって中止」何を意味するのに何もゾンビプロセスを?クライアントは接続を終了しようとしますか?または、別のエンドポイントにヒットしますか?私はFlaskを使用してこれを行う方法はないと思っていますが、エンドポイントをコード化して処理を停止できるようにすることは可能ですが(データベースを使用してこれらのタスクを追跡し、停止フラグなど)。 –

+0

彼らは接続を閉じます。私はいくつかのオプション(チェックボックス)を変更するたびにイメージを再生成します:新しいボックスをチェックすると、リクエストが開始されます。最初のリクエストが完了する前にすぐに2番目のボックスをチェックすると、最初のリクエストはキャンセルされます(jqXHR.abort() )新しいオプションで新しいものが作られます。私はクライアントからあなたが示唆したようにいくつかの "wascancelled"ファイル/ DBレコードを書くという余分な要求を発したと思ったが、それは非常に醜いようだ。 PHPにはconnection_aborted()があり、nodejsにはreq.on( 'close')があります。 – Crashthatch

+2

[このメールスレッド](https://groups.google.com/forum/#!topic/modwsgi/jr2ayp0xesk)が興味深いかもしれません。ここでは、WSGIアプリケーションが接続が閉じられたときを検出する方法について説明します。 PHPで 'connection_aborted()'がどのように動作するのかと似ていると思います。単純に呼び出すだけで、接続が閉じられたかどうかを判断することはできません。代わりに、最初にデータを送り返そうとする必要があります(これは[streaming](http://flask.pocoo.org/docs/patterns/streaming/)を使用して取り除くことができます)。 –

答えて

12

あなたの問題に対する潜在的な...ハックな解決策がありますFlask has the ability to stream content back to the user via a generator。ハッキーな部分は、接続がまだ開いているかどうかを確認するためにブランクデータをストリーミングしています。ジェネレーターは処理が完了したかどうかをチェックして、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

+0

これまでのベストソリューション、それを見ていただきありがとうございます! – blakev

+1

例外はどこで発生していますか?どのようにキャプチャすることができますか? – Guy

+1

エラーはソケットライブラリで生成されます。これは、もはや開いていないソケットにデータを送信しようとしたときに生成され、タイムアウトが発生します。 – AlexLordThorsen

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) 

はたぶん、あなたはリクエストがあなたが接続毎秒の状態をチェック__init__にスレッドを作成することができます来るときより、カスタムrequest_handlerとして作成されたビットを調査したい:例えば

接続が閉じていることを検出すると(check this thread)、画像処理を停止します。しかし、私はこれがちょっと複雑だと思っています:。

+0

これを試してみましたが、 'connection_dropped()'を起動しませんでした。私はIOError:[Errno 32] Broken pipeのトレースを取得しただけです。 –

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. フラスコの発電機能
  2. を使用して、データのインスタントストリーミングにキャンセル接続
+0

完全な例を記述してください。どこにこのコードを置く必要がありますか?プロセスは何ですか? –

関連する問題