我正在尝试在heroku上部署一个使用Celery中的后台任务的烧瓶应用程序。我已经实现了application factory pattern,以便芹菜进程不会被烧瓶app的任何一个实例绑定。
这在本地工作,我还没有看到错误。但是当部署到heroku时,总是会出现相同的结果:芹菜任务(我只使用一个)在第一次运行时成功,但任何后续芹菜调用该任务都失败了sqlalchemy.exc.DatabaseError: (psycopg2.DatabaseError) SSL error: decryption failed or bad record mac
。如果我重新开始芹菜工作,那么循环就会继续。
有multiple issues显示相同的error,但都没有指定正确的解决方案。我最初认为实现应用程序工厂模式会阻止此错误显示,但它并不存在。
在app/__init__.py
中,我创建了芹菜和数据库对象:
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 worker -A app.flask_celery.celery --loglevel=info
这就是实际芹菜任务的样子:
@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)
图书馆版本
答案 0 :(得分:5)
解决方案是在任务开始时添加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()