更新:それ以来、最新のフラスコのドキュメントに記載されているパターンに基づいて、アプリケーションの分解を処理し、タスクごとにセットアップするためのより良い方法を使用し始めました。
extends.py
import flask
from flask.ext.sqlalchemy import SQLAlchemy
from celery import Celery
class FlaskCelery(Celery):
def __init__(self, *args, **kwargs):
super(FlaskCelery, self).__init__(*args, **kwargs)
self.patch_task()
if 'app' in kwargs:
self.init_app(kwargs['app'])
def patch_task(self):
TaskBase = self.Task
_celery = self
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
if flask.has_app_context():
return TaskBase.__call__(self, *args, **kwargs)
else:
with _celery.app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
self.Task = ContextTask
def init_app(self, app):
self.app = app
self.config_from_object(app.config)
celery = FlaskCelery()
db = SQLAlchemy()
app.py
from flask import Flask
from extensions import celery, db
def create_app():
app = Flask()
#configure/initialize all your extensions
db.init_app(app)
celery.init_app(app)
return app
この方法でアプリを設定すると、必要に応じてすべてのタスクがアプリケーションコンテキストで自動的に実行されるため、アプリケーションコンテキスト内から明示的に実行しなくても、セロリを実行して使用できます。管理する重要な問題であるタスク後の分解について明示的に心配する(以下の他の応答を参照)。
トラブルシューティング
取得し続ける人は、次のwith _celery.app.app_context(): AttributeError: 'FlaskCelery' object has no attribute 'app'
ことを確認してください。
celery
インポートはapp.py
ファイルレベルで保持します。避ける:
app.py
from flask import Flask
def create_app():
app = Flask()
initiliaze_extensions(app)
return app
def initiliaze_extensions(app):
from extensions import celery, db # DOOMED! Keep celery import at the FILE level
db.init_app(app)
celery.init_app(app)
- あなたの前にあなたのセロリ労働者を始めて
flask run
、使用してください
celery worker -A app:celery -l info -f celery.log
app:celery
、つまりからの読み込みに注意してくださいapp.py
。
拡張機能からインポートして、タスクを装飾することもできますfrom extensions import celery
。
以下の古い答えはまだ機能しますが、解決策ほどきれいではありません
私は、アプリケーションのコンテキストでcelery.start()を呼び出す別のファイルを作成することにより、アプリケーションコンテキスト内ですべてのセロリを実行することを好みます。これは、タスクファイルにコンテキストの設定や分解を散らかす必要がないことを意味します。また、フラスコの「アプリケーションファクトリ」パターンにも適しています。
extends.py
from from flask.ext.sqlalchemy import SQLAlchemy
from celery import Celery
db = SQLAlchemy()
celery = Celery()
tasks.py
from extensions import celery, db
from flask.globals import current_app
from celery.signals import task_postrun
@celery.task
def do_some_stuff():
current_app.logger.info("I have the application context")
#you can now use the db object from extensions
@task_postrun.connect
def close_session(*args, **kwargs):
# Flask SQLAlchemy will automatically create new sessions for you from
# a scoped session factory, given that we are maintaining the same app
# context, this ensures tasks have a fresh session (e.g. session errors
# won't propagate across tasks)
db.session.remove()
app.py
from extensions import celery, db
def create_app():
app = Flask()
#configure/initialize all your extensions
db.init_app(app)
celery.config_from_object(app.config)
return app
RunCelery.py
from app import create_app
from extensions import celery
app = create_app()
if __name__ == '__main__':
with app.app_context():
celery.start()