web-dev-qa-db-ja.com

Flaskリクエストで壊れたパイプ

ローカルのRESTリクエストをflaskアプリで送信して、次のようにしたい:

from flask import Flask, url_for, request
import requests

app = Flask(__name__)

@app.route("/<name>/hi", methods=["POST"])
def hi_person(name):
    form = {"name": name}
    return requests.post(url_for("hi", _external=True), data=form)

@app.route("/hi", methods=["POST"])
def hi():
    return 'Hi, %s!' % request.form["name"]

送信 curl -X POST http://localhost:5000/john/hiにより、flaskアプリ全体がフリーズします。キル信号を送信すると、パイプ破損エラーが発生します。flask=ここで凍る?

49
jfocht

flask= appを、同時リクエストを処理できる適切なWSGIサーバー(おそらく gunicorn または WSGI )で実行すると動作します。開発中、Flaskが提供するサーバーでスレッドを有効にします。

app.run(threaded=True)

ただし、Flask=サーバーは実稼働での使用は推奨されていません。Flask 1.0では、threadedはデフォルトで有効になっており、 d実際にアプリを実行するために、コマンドラインでflaskコマンドを使用したい。

何が起こるかというと、リクエストを使用して、flaskアプリにsecondリクエストを行っていますが、まだビジー状態なので最初の要求を処理すると、この最初の要求が完了するまで、この2番目の要求には応答しません。

ちなみに、Python 3の下で、socketserverの実装は切断をより適切に処理し、クラッシュするのではなく提供し続けます。

106
Martijn Pieters

ここではいくつかのことが行われていますが、一度に1つずつ対処していきます。

まず、おそらくおもちゃの開発サーバーを使用しています。このサーバーには多くの制限があります。これらの制限の主な理由は、一度に1つの要求しか処理できないことです。最初のリクエスト中に2番目のリクエストを作成すると、アプリケーションがロックされます:requests.post()関数はFlaskが応答するのを待っていますが、Flask自体はpost()が戻るのを待っています!この特定の問題の解決策は、WSGIアプリケーションをマルチスレッドまたはマルチプロセス環境で実行することです。 http: //twistedmatrix.com/trac/wiki/TwistedWeb ですが、他にもいくつかのオプションがあります。

邪魔にならないように...これはアンチパターンです。 2つのビュー間で一部の機能を共有するためだけに、HTTPリクエストのオーバーヘッドをすべて呼び出すことはほとんどありません。行うべき正しいことは、その共有作業を行う別の関数をリファクタリングすることです。あなたの特定の例をリファクタリングすることはできません。なぜなら、あなたが持っているものは非常にシンプルで、実際には2つのビューに値するものでもないからです。正確に何を構築したいですか?

編集:コメントは、おもちゃのstdlibサーバーのマルチスレッドモードでデッドロックの発生を防ぐのに十分かどうかを尋ねます。 「たぶん」と言います。はい。両方のスレッドの進行を妨げる依存関係がなく、両方のスレッドがネットワーキングタスクを完了するのに十分な進行をしている場合、リクエストは正しく完了します。ただし、2つのスレッドが相互にデッドロックするかどうかを決定することは決定できず(証拠が鈍いため省略されています)、stdlibサーバーが正しく実行できることを確信するつもりはありません。

19
Corbin

クラッシュを引き起こしたバグは Version 0.12 で修正され、2016年12月21日にリリースされました。これは多くの人が待ち望んでいた重要な修正です。

Flask changelogから:

  • 内部サーバーエラー(プル要求#2006)を返す代わりに、開発サーバーをクラッシュさせた動作の変更を元に戻します。
5
arotman

私はpostメソッドでも同じ問題を抱えていましたが、一般的に私のpostメソッドは何もしていませんでした。

return _socket.socket.send(self._sock, data, flags) urllib3.exceptions.ProtocolError:
('Connection aborted.', BrokenPipeError(32, 'Broken pipe'))

if request.method == 'POST':
    print(len(request.data))
return 'dummy'

これはprintがトリックをしました

0
Taras Vaskiv