[解決済み] Flaskがレスポンスを返した後に関数を実行する
質問
以下のコードを実行する必要があります。 の後に を実行する必要があります。そのためにCeleryのようなタスクキューをセットアップするほど複雑だとは思いません。重要な要件は、Flaskはこの関数を実行する前にクライアントにレスポンスを返さなければならないということです。関数が実行されるのを待つことはできないのです。
これに関するいくつかの既存の質問がありますが、どの回答も、レスポンスがクライアントに送信された後にタスクを実行することに対処していないようです、それらはまだ同期的に実行され、その後レスポンスが返されます。
どのように解決するのですか?
長い話になりますが、Flaskはこれを実現するための特別な機能を提供していません。単純な一回限りのタスクであれば、以下のようなPythonのマルチスレッドを検討してください。より複雑な構成の場合は、RQやCeleryのようなタスクキューを使用します。
なぜですか?
Flaskが提供する関数とその理由を理解することは重要です。 をしないのか? が意図した目標を達成できないのかを理解することが重要です。これらはすべて他のケースでは有用であり、良い読み物ですが、バックグラウンドタスクでは役に立ちません。
Flask の
after_request
ハンドラ
Flaskの
after_request
ハンドラで、詳しくは
この遅延リクエストコールバックのパターンは
と
このスニペットは、リクエストごとに異なる関数をアタッチするためのものです。
のようにすると、コールバック関数にリクエストが渡されます。意図する使用例としては
リクエストを変更する
例えば、クッキーを添付するような場合です。
このように、リクエストはこれらのハンドラが実行を終えるまで待機します。なぜなら、結果的にリクエスト自体が変更されることを期待しているからです。
Flaskの
teardown_request
ハンドラ
これは
after_request
と似ていますが
teardown_request
は受信しません。
request
オブジェクトを受け取りません。ということは、リクエストを待たないということですよね?
これは解決策のようで、次のように Stack Overflow の同様の質問に対するこの回答 が示唆しています。そして、Flaskのドキュメントには、次のように説明されています。 のコールバックは実際のリクエストから独立しています。 であり、リクエストコンテキストを受け取らないとFlaskのドキュメントで説明されているので、これを信じる十分な理由があるでしょう。
残念ながら
teardown_request
はまだ同期ですが、これは Flask のリクエスト処理の後半で、リクエストがもはや変更不可能になったときに起こるだけです。Flask は
<は
は依然としてティアダウン関数
が完了するのを待ってからレスポンスを返します。
このFlaskのコールバックとエラーのリスト
が指示します。
Flaskのストリーミングレスポンス
Flask はジェネレータを渡すことでレスポンスをストリームすることができます。
Response()
というように
このStack Overflowの回答は、同様の質問に対して
が示唆します。
ストリーミングでは、クライアントが が行います。 はリクエストが終了する前にレスポンスの受信を開始します。しかし、リクエストはまだ同期的に実行されるので、 リクエストを扱うワーカーはストリームが終了するまでビジー状態です。
このストリーミングのためのFlaskパターン
を使用するためのドキュメントが含まれています。
stream_with_context()
を使うことについてのドキュメントがあります。これはリクエストコンテキストを含めるために必要です。
では、解決策は?
Flaskはバックグラウンドで関数を実行するソリューションを提供していません。
ほとんどの場合、この問題を解決する最善の方法は、RQやCeleryのようなタスクキューを使うことです。これはこの種の質問に対する最も一般的な回答です。なぜなら、それが最も正しく、コンテキストなどを正しく考慮する方法で物事を設定するよう強制されるからです。
バックグラウンドで関数を実行する必要があり、これを管理するためにキューをセットアップしたくない場合、Pythonのビルトインである
threading
または
multiprocessing
でバックグラウンドワーカーを起動します。
にはアクセスできません。
request
などの Flask のスレッドロカールにバックグラウンドタスクからアクセスすることはできません。代わりに、ビューを作成するときに、ビューから必要なデータをバックグラウンドスレッドに渡します。
@app.route('/start_task')
def start_task():
def do_work(value):
# do something that takes a long time
import time
time.sleep(value)
thread = Thread(target=do_work, kwargs={'value': request.args.get('value', 20)})
thread.start()
return 'started'
関連
-
[解決済み] 関数デコレータを作成し、それらを連鎖させるには?
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] 関数内でグローバル変数を使用する
-
[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。
-
[解決済み] モジュールの関数名(文字列)を使って、モジュールの関数を呼び出す。
-
[解決済み] Flaskのリクエストで受信したデータを取得する
-
[解決済み] Flaskで静的ファイルを提供する方法
-
[解決済み] FlaskのビューからJSONレスポンスを返す
-
[解決済み] Django で全てのリクエストヘッダを取得するにはどうすれば良いですか?
-
[解決済み] Flaskで非同期タスクを作る
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ctrl-cを使わずにflaskアプリケーションを停止する方法
-
[解決済み] 前月の日時オブジェクトを返す
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] バブルソートの宿題
-
[解決済み] Django Rest Framework ファイルアップロード
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] Celeryタスクのユニットテストはどのように行うのですか?
-
[解決済み] if 節の終了方法
-
[解決済み] Python 言語を決定するには?
-
[解決済み] Pythonの文字列の前にあるbという接頭辞は何を意味するのですか?