我正在尝试在 heroku 上部署一个 flask 应用程序,该应用程序在 Celery 中使用后台任务。我已经实现了 application factory pattern这样 celery 进程就不会绑定(bind)到 flask 应用程序的任何一个实例。
这在本地有效,我还没有看到错误。但是当部署到 heroku 时,总是会出现相同的结果:celery 任务(我只使用一个)在第一次运行时成功,但是对该任务的任何后续 celery 调用都会失败并出现 sqlalchemy.exc.DatabaseError: (psycopg2.DatabaseError) SSL 错误:解密失败或错误记录 mac。如果我重新启动 celery worker,循环将继续。
有multiple issues显示相同的 error ,但没有指定适当的解决方案。我最初认为实现应用程序工厂模式可以防止出现此错误,但事实并非如此。
在 app/__init__.py 我创建了 celery 和 db 对象:
celery = Celery(__name__, broker=Config.CELERY_BROKER_URL)
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
db.init_app(app)
return app
我的 flask_celery.py 文件创建了实际的 Flask 应用程序对象:
import os
from app import celery, create_app
app = create_app(os.getenv('FLASK_CONFIG', 'default'))
app.app_context().push()
我用这个命令启动 celery : celery worker -A app.flask_celery.celery --loglevel=info
实际的 celery 任务是这样的:
@celery.task()
def task_process_stuff(stuff_id):
stuff = Stuff.query.get(stuff_id)
stuff.processed = True
db.session.add(stuff)
db.session.commit()
return stuff
调用者:
task_process_stuff.apply_async(args=[stuff.id], countdown=10)
库版本
- flask 0.12.2
- SQLAlchemy 1.1.11
- Flask-SQLAlchemy 2.2
- celery 4.0.2
请您参考如下方法:
解决方案是在任务的开头添加 db.engine.dispose(),在任何工作开始之前处理所有数据库连接:
@celery.task()
def task_process_stuff(stuff_id):
db.engine.dispose()
stuff = Stuff.query.get(stuff_id)
stuff.processed = True
db.session.commit()
return stuff
因为我的所有任务都需要这个功能,所以我将它添加到 task_prerun:
@task_prerun.connect
def on_task_init(*args, **kwargs):
db.engine.dispose()
