Python 在多个uWSGI过程中使用炼金术
我一直在与Flask应用程序中的一个持续错误作斗争:Python 在多个uWSGI过程中使用炼金术,python,mysql,flask,sqlalchemy,flask-sqlalchemy,Python,Mysql,Flask,Sqlalchemy,Flask Sqlalchemy,我一直在与Flask应用程序中的一个持续错误作斗争: OperationalError: (_mysql_exceptions.OperationalError) (2006, 'MySQL server has gone away') 我正在使用mySQL服务器实例和Flask SQLAlchemy模块。我仔细检查了mySQL实例上连接的过期时间和SQLAlchemy配置中的重置时间。没有问题,连接池在mySQL连接过期之前重置。我得出的结论是,一定是有什么问题导致连接关闭,然后该连接的下一
OperationalError: (_mysql_exceptions.OperationalError) (2006, 'MySQL server has gone away')
我正在使用mySQL服务器实例和Flask SQLAlchemy模块。我仔细检查了mySQL实例上连接的过期时间和SQLAlchemy配置中的重置时间。没有问题,连接池在mySQL连接过期之前重置。我得出的结论是,一定是有什么问题导致连接关闭,然后该连接的下一个用户阻塞
我正在使用uWSGI运行Flask应用程序,uWSGI生成了四个进程。如果切换到单个进程,则无法重现错误。我猜进程是通过共享连接池相互踩踏的。我添加了以下函数,以便在uWSGI分叉进程时运行
from uwsgidecorators import postfork
@postfork
def reset_db_connections():
db.engine.dispose()
启动时工作正常,当多个请求同时进入时,似乎可以解决问题。但是,现在当一个进程被重置时,该进程上的下一个请求会出现一个类似但不相同的SQL Server消失错误。以下是数据库的初始设置代码
def configure_db():
from my_application.models import SomeModel
db.create_all()
db = SQLAlchemy(app, session_options={'expire_on_commit': False})
configure_db()
数据库的典型用法如下所示:
def save(self):
try:
db.session.add(self)
db.session.commit()
except Exception, ex:
app.logger.error("Error saving campaign: %s" % ex)
db.session.rollback()
Reads是以下两种风格之一:
user = db.session.query(User).filter(User.email == email).scalar()
user = User.query.filter(User.email == email).scalar()
我的理解是Flask SQLAlchemy使用范围会话,因此它们应该在多进程环境中提供一些保护。我需要重置fork上的连接池吗?分叉时我是否也应该检查实时会话
更新:
我已将叉子更改为:
@postfork
def reset_db_connections():
db.session.close_all()
db.engine.dispose()
db.create_scoped_session()
我仍然得到操作错误,但它只发生在fork期间,并且似乎不会干扰请求。堆栈跟踪不包括fork,但这不允许我捕获它
回溯(最近一次呼叫最后一次):
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/pool.py”,
第636行,在
仙女。重置(池)
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/pool.py”,
第774行,输入复位
self.\u reset\u agent.rollback()
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/engine/base.py”,
第1563行,在回滚中
self.\u do\u rollback()
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/engine/base.py”,
第1601行,in_do_回滚
self.connection.\u回滚\u impl()
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/engine/base.py”,
第670行,在“回滚”impl中
self.\u handle\u dbapi\u异常(e,None,None,None,None)
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/engine/base.py”,
第1341行,在_handle_dbapi_异常中
exc_信息
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/util/compat.py”,
第199行,从原因提升
重新释放(类型(异常),异常,tb=exc_tb)
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/engine/base.py”,
第668行,在“回滚”impl中
self.engine.dialogue.do_回滚(self.connection)
文件
“/home/vagrant/env/local/lib/python2.7/site packages/sqlalchemy/dialogs/mysql/base.py”,
第2519行,在do_回滚中
dbapi_连接.回滚()
您必须使用lazy apps=true选项来设置uwsgi 看看这个答案: 我不会使用“lazy”选项,因为它已被弃用 当使用主进程处理多个进程时,uwsgi 在主进程中初始化应用程序,然后复制 应用程序转移到每个工作进程。问题是如果你打开一个 数据库连接在初始化应用程序时 多个进程共享同一连接,这会导致错误 上面 在某些情况下,如使用flask_admin或在
app/\uuuu init\uuuuuuuuuuupy
中调用Base.metadata.create_all()
,您的应用确实在导入时已经与数据库建立了连接。使用lazy apps=false
uwsgi在导入模块后分叉,从而将连接的文件描述符复制到子级。使用lazy apps=true
uwsgi自身分叉,然后进行导入。这样,每个子进程都有自己的连接
uWSGI尝试(ab)使用fork()调用的Copy-On-Write语义
只要可能。默认情况下,它将在加载
应用程序共享尽可能多的内存。如果这
由于某些原因,这种行为是不受欢迎的,请使用lazy apps选项。
这将指示uWSGI在每个工作人员完成任务后加载应用程序
fork()