web-dev-qa-db-ja.com

Python Flaskフレームワークで繰り返しタスクを実行するには?

私は訪問者にいくつかの情報を提供するウェブサイトを構築しています。この情報は、5秒ごとにいくつかの外部APIをポーリングすることにより、バックグラウンドで集約されます。現在の動作方法は、 APScheduler ジョブを使用することです。システム全体の移植が容易になるため、最初はAPSchedulerを好みました(新しいマシンにcronジョブを設定する必要がないため)。次のようにポーリング機能を開始します。

_from apscheduler.scheduler import Scheduler

@app.before_first_request
def initialize():
    apsched = Scheduler()
    apsched.start()

    apsched.add_interval_job(checkFirstAPI, seconds=5)
    apsched.add_interval_job(checkSecondAPI, seconds=5)
    apsched.add_interval_job(checkThirdAPI, seconds=5)
_

これは少しは機能しますが、いくつかの問題があります。

  1. まず第一に、これは間隔ジョブがFlask=コンテキストの外側で実行されていることを意味します。これまではそれほど問題ではありませんでしたが、エンドポイントの呼び出しに失敗した場合、システムにメールを送ってください(「API Xの呼び出しに失敗しました」)。Flaskコンテキスト内で実行されないため、 flask-mail 実行される(RuntimeError('working outside of application context'))。
  2. 第二に、Flaskビルトインデバッグサーバーを使用しない場合に、これがどのように動作するのか疑問に思いますが、実稼働サーバーでは4人のワーカーを使用できます。回ですか?

全体として、これらの繰り返しタスクを実行するためのより良い方法があるべきだと感じていますが、どのようにしたらよいかわかりません。誰かがこの問題の興味深い解決策を持っていますか?すべてのヒントを歓迎します!

[編集] Celeryschedules で読んでいます。 CeleryがAPSchedulerとどのように違うのか、それが私の2つのポイントを解決できるかどうかは本当にわかりませんが、これを読んでいる人がCeleryでもっと調査する必要があると思いますか?

[結論]約2年後、私はこれを読んでおり、私が最終的に何をしたかを皆さんに知らせることができると思いました。 @BluePeppersは、Flaskエコシステムにあまり縛られてはいけない。これは少し複雑になります(Ansibleを学習し、毎分実行するのに十分なコードを変換する必要がありました)これはより堅牢だと思います。現在、素晴らしい pythonr-rq を使用しています= a-syncジョブのキューイング(APIの確認とメールの送信)。 rq-scheduler について知りましたが、まだテストしていませんが、だから、これはこの質問の将来の読者のためのヒントかもしれません。

残りの部分については、みなさんの美しい一日をお祈りします!

26
kramer65

(1)

app.app_context()コンテキストマネージャーを使用して、アプリケーションコンテキストを設定できます。使い方は次のようになると思います。

from apscheduler.scheduler import Scheduler

def checkSecondApi():
    with app.app_context():
        # Do whatever you were doing to check the second API

@app.before_first_request
def initialize():
    apsched = Scheduler()
    apsched.start()

    apsched.add_interval_job(checkFirstAPI, seconds=5)
    apsched.add_interval_job(checkSecondAPI, seconds=5)
    apsched.add_interval_job(checkThirdAPI, seconds=5)

または、デコレータを使用することもできます

def with_application_context(app):
    def inner(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            with app.app_context():
                return func(*args, **kwargs)
        return wrapper
    return inner

@with_application_context(app)
def checkFirstAPI():
    # Check the first API as before

(2)

はい、それはまだ動作します。唯一の(重要な)違いは、アプリケーションが世界と直接通信しないことです。リバースプロキシまたはfastcgi/uwsgi/whateverを介した何かを経由します。唯一の懸念は、起動しているアプリのインスタンスが複数ある場合、複数のスケジューラが作成されることです。これを管理するには、バックエンドタスクをFlaskアプリケーションから移動し、タスクを定期的に実行するために設計されたツール(Celeryなど)を使用することをお勧めします。これのマイナス面は、 Flask-Mailのようなものを使用することはできますが、imo、Flaskエコシステム; Flask-Mailを標準で使用することで得られるもの、非Flask、メールライブラリ?

また、アプリケーションを分割すると、1つのモノリシックWebアプリケーションを使用する場合と比較して、容量が必要なときに個々のコンポーネントを簡単にスケールアップできます。

24
BluePeppers