web-dev-qa-db-ja.com

flaskアプリケーションの開始後にコードを実行

私の目標は、Flaskアプリケーションが開始された後に実行する任意のコードを取得することです。ここに私が持っているものがあります:

_def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)
_

理想的にはこれを行うことができます:

_def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)
    some_code()
_

ただし、コードはapp.run()を超えて継続しないため、some_code()は実行されません。

私が現在取り組んでいる解決策は、app.run()とは別のスレッドでsome_code()を実行し、これを設定する 最初の要求の前 関数を作成することです。

_app.is_running = True
_

次に、some_code()を取得して、アプリへの基本的なリクエストを撮影し、「最初のリクエストの前」コードが実行されるようにします。これはかなり複雑であり、文書化するのは難しいでしょう。むしろ、Flaskで既に提供されているapp.is_runningパラメーターを使用するか、_@app.after_server_start_デコレーターを使用しますが、私の知る限り、どちらも存在しません。

このコードの改善にご協力ください。


死後:この問題について考えるたびに、_@app.after_server_start_デコレーターが存在することを望みます。

31
Cyrin

flaskアプリケーションが開始された後、厳密に最初のリクエストの前にコードを実行する必要がある場合、@ app.before_first_requestが処理できるため、最初のリクエストの実行によってもトリガーされません。 CESCOが述べたようにFlask_Scriptを使用しますが、runserverコマンドを@ manager.commandで上書きする代わりに、クラスServerをサブクラス化して__ call __メソッドを上書きできます。

from flask import Flask
from flask_script import Manager, Server

def custom_call():
    #Your code
    pass

class CustomServer(Server):
    def __call__(self, app, *args, **kwargs):
        custom_call()
        #Hint: Here you could manipulate app
        return Server.__call__(self, app, *args, **kwargs)

app = Flask(__name__)
manager = Manager(app)

# Remeber to add the command to your Manager instance
manager.add_command('runserver', CustomServer())

if __name__ == "__main__":
    manager.run()

この方法では、runserverコマンドのデフォルトオプションを上書きしません。

23
Ismael

Flask-Script を使用してアプリを実行し、runserverクラス/メソッドを次のように上書きします

# manage.py

from flask.ext.script import Manager

from myapp import app

manager = Manager(app)

def crazy_call():
    print("crazy_call")

@manager.command
def runserver():
    app.run()
    crazy_call()

if __name__ == "__main__":
    manager.run()
9
CESCO

私はちょうど_main.py_で実行された_python main.py_でした:

_with app.app_context():
    from module import some_code()
    some_code()

def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)
_

上記で提供されたより包括的な回答なしで、これはうまくいきました。私の場合、some_code()は_flask_caching.Cache_を介してキャッシュを初期化しています。

しかし、おそらく_some_code_が正確に何をしているかに依存します...

2
jtlz2

私はflask私のアプリでこの問題に遭遇しました。アプリの起動時にスケジューラーを開始し、定期的にいくつかのジョブを開始したかったです。私がやったことは、200を返す「ヘルスチェック」エンドポイントを追加することであり、私のDockerファイルでそのエンドポイントを設定しました:

HEALTHCHECK CMD curl --fail http://localhost:8080/alive || exit 1

デフォルトの動作では、30秒ごとにそのコマンドが実行され、最初の実行ではinit()メソッドが開始されます。 https://docs.docker.com/engine/reference/builder/#healthcheck

0
skelly

これを行うためにFlask-Scriptを必要とせず、すべてのプロジェクトが既にFlask-Scriptを使用するわけではないため、上記のメソッドはどれも好きではありません。

最も簡単な方法は、独自のFlaskサブクラス。Flask(__name__)を使用してアプリを構築する場合、独自のクラスを追加して代わりに使用することです。

_def do_something():
  print('MyFlaskApp is starting up!')


class MyFlaskApp(Flask):
  def run(self, Host=None, port=None, debug=None, load_dotenv=True, **options):
    if not self.debug or os.getenv('WERKZEUG_RUN_MAIN') == 'true':
      with self.app_context():
        do_something()
    super(MyFlaskApp, self).run(Host=host, port=port, debug=debug, load_dotenv=load_dotenv, **options)


app = MyFlaskApp(__name__)
app.run()
_

もちろん、これは実行されませんafter開始しますが、正しいbeforerun()が最終的に呼び出されます。アプリコンテキストを使用すると、データベースやアプリコンテキストを必要とする他の操作で必要なことができるようになります。これは、すべてのサーバー(uwsgi、gunicornなど)でも機能するはずです。

do_something()を非ブロッキングにする必要がある場合は、代わりにthreading.Thread(target=do_something).start()を使用して単純にスレッド化できます。

条件ステートメントは、デバッグモード/リローダーを使用するときに二重呼び出しを防ぐことです。

0
jslay