2017-03-14 12 views
1

Sqlalchemyユーザー入力を介して重いSQLクエリを実行する必要があるFlaskウェブアプリケーションがあります。クエリのタイムアウトを設定したいと思います.20秒としましょう。クエリが20秒以上かかると、サーバーはユーザーにエラーメッセージを表示して、後で入力をやり直すことができます。Flaskで長いSQLクエリを処理する方法は?

Flask開発サーバーとGunicornの両方で、multiprocessingthreadingモジュールの両方を試してみました。サーバーはブロックされ続け、エラーメッセージは返されません。以下に、コードの抜粋を示します。

どのようにユーザーフレンドリーな方法でFlaskで遅いSQLクエリを処理しますか?

ありがとうございました。

from multiprocessing import Process 

@app.route("/long_query") 
def long_query(): 
    query = db.session(User) 

    def run_query(): 
     nonlocal query 
     query = query.all() 

    p = Process(target=run_query) 
    p.start() 

    p.join(20) # timeout of 20 seconds 
    if p.is_alive(): 
     p.terminate() 
     return render_template("error.html", message="please try with smaller input") 

    return render_template("result.html", data=query) 

答えて

4

Celeryなどを使用することをお勧めします(単純なワークフローではpython-rqを使用します)。 セロリに関するフラスコのドキュメントを見てみましょう:長時間実行クエリの結果に対処するためとしてhttp://flask.pocoo.org/docs/0.12/patterns/celery/

:結果が利用可能になるまで、あなたは、タスクの結果を要求し、クライアントアプリケーションが定期的にこのエンドポイントをチェックしているため、エンドポイントを作成することができます。

+0

ありがとうございました!私は実際に 'python-rq'を既にこのWebアプリケーションの別の部分に使用しています。重いSQLクエリを処理するより簡単な方法を探していますが、' celery'と思われ、 'python-rq'がやり方ですこの問題。 – Son

2

leovpに言及したように、セロリはあなたが長期的なプロジェクトに取り組んでいるなら行く方法です。しかし、セットアップが簡単な小さなプロジェクトで作業している場合は、RQとし、flask pluginとすることをお勧めします。あなたが本当にクエリを終了したい場合にもまあ


(例えば、彼らはデシベルで持っているロックを解放する)彼らは自分たちの後にクリーンアップすることができない場合がありますので、彼らは、データベースを照会している間のプロセスを終了さについて非常に真剣に考えてタイムアウトでは、それをサポートするデータベースを使用することをお勧めします(PostgreSQLは1つです)。このセクションではPostgreSQLを使用すると仮定します。

from sqlalchemy.interfaces import ConnectionProxy 

class ConnectionProxyWithTimeouts(ConnectionProxy): 

    def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): 

     timeout = context.execution_options.get('timeout', None) 

     if timeout: 
      c = cursor._parent.cursor() 
      c.execute('SET statement_timeout TO %d;' % int(timeout * 1000)) 
      c.close() 

      ret = execute(cursor, statement, parameters, context) 

      c = cursor._parent.cursor() 
      c.execute('SET statement_timeout TO 0') 
      c.close() 
      return ret 
     else: 
      return execute(cursor, statement, parameters, context) 

あなたがエンジンを作成したとき、あなたはあなた自身の接続プロキシ

engine = create_engine(URL, proxy=TimeOutProxy(), pool_size=1, max_overflow=0) 

なり、あなたは上記のコードを使用したい場合は、この

User.query.execution_options(timeout=20).all() 

のように、クエリ可能性があり、使用私は100%バグがないと確信しているわけではないので、あなた自身の実装のための基礎としてのみです。

+0

あなたの提案をありがとう! sqlalchemy内でクエリが実行された場合、python-rq(またはセロリ)でsqlクエリをきれいに終了できますか? – Son

+1

@Son答えを更新しました。 –

関連する問題