我正在使用Flask-SQLAlchemy 1.0,Flask 0.10,SQLAlchemy 0.8.2和Python 2.7.5。我正在使用Oracle的MySQL Connector / Python 1.0.12连接MySQL 5.6。
当我重新启动我的Web服务器(Apache2或Flask的内置)时,在OperationalError: MySQL Connection not available
到期后(默认为8小时),我收到异常wait_timeout
。
我找到了similar problems人,并明确设置了SQLALCHEMY_POOL_RECYCLE = 7200
,即使是Flask-SQLAlchemy's default。当我设置断点here时,我看到拆解功能在每次请求后成功调用session.remove()
。有什么想法吗?
2014年7月21日更新:
由于这个问题一直受到关注,我必须补充一点,我做了尝试了一些提案。我的两次尝试看起来如下:
首先
@contextmanager
def safe_commit():
try:
yield
db.session.commit()
except:
db.session.rollback()
raise
这允许我像这样包装我的提交调用:
with safe_commit():
model = Model(prop=value)
db.session.add(model)
我99%肯定我没有错过使用此方法的任何db.session.commit
来电,我仍然遇到问题。
第二
def managed_session():
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
try:
response = f(*args, **kwargs)
db.session.commit()
return response
except:
db.session.rollback()
raise
finally:
db.session.close()
return decorated_function
return decorator
为了进一步确保我没有错过任何提交调用,我创建了一个Flask包装器,启用了代码,如(如果我没记错的话):
@managed_session()
def hello(self):
model = Model(prop=value)
db.session.add(model)
return render_template(...
不幸的是,两种方法都没有效果。我还记得尝试发出SELECT(1)调用以尝试重新建立连接,但我不再拥有该代码。
对我来说,底线是MySQL / SQL Alchemy有问题。当我迁移到Postgres时,我不必担心我的提交。一切正常。
答案 0 :(得分:6)
我遇到了这个问题,这让我疯了。我尝试使用SQLALCHEMY_POOL_RECYCLE,但这似乎无法解决问题。
我终于找到http://docs.sqlalchemy.org/en/latest/orm/session.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it,并改编为flask-sqlalchemy。
在我开始使用以下模式后,我没有看到问题。关键似乎总是确保执行commit()
或rollback()
。因此,如果if-then-else不流经commit()
(例如,对于检测到的错误),则在重定向,中止,render_template调用之前也执行commit()
或rollback()
。 / p>
class DoSomething(MethodView):
def get(self):
try:
# do stuff
db.session.commit()
return flask.render_template('sometemplate.html')
except:
db.session.rollback()
raise
app.add_url_rule('/someurl',view_func=DoSomething.as_view('dosomething'),methods=['GET'])
更新2014年7月22日
我发现我还必须将SQLALCHEMY_POOL_RECYCLE更改为小于MySQL interactive_timeout。在godaddy服务器上,interactive_timeout设置为60,所以我将SQLALCHEMY_POOL_RECYCLE设置为50.我认为我使用的模式和此超时都是使问题消失所必需的,但此时我并不积极。但是,我很确定当SQLALCHEMY_POOL_RECYCLE大于interactive_timeout时,我仍然遇到操作错误。
答案 1 :(得分:1)
我最近遇到了同样的问题 - 经过很长一段时间的FLASK&和MYSQL数据库之后的第一次请求。 SQLAlchemy应用程序不活动(至少8小时)会导致未处理的异常,这反过来意味着 500内部服务器错误:连接不可用。所有后续请求都没问题。
我设法将问题归结为MYSQL连接,将 @@ session.wait_timeout (以及 @@ global 以防万一)值减少到5秒。然后每个奇怪的请求都是正常的,而在5加一秒的停顿后每秒都失败了。结论很明显 - SQLAlchemy使用open,但是在数据库端连接上有时间。
就我而言,事实证明该解决方案已在SQLAlchemy – MYSQL has gone away博文中详细说明:
首先要确定的是 pool_recycle 的值应该小于你的MYSQL wait_timeout 值。
在MYSQL文档中,您可以找到 wait_timeout 默认为8小时(28 800秒),而SQLAlchemy引擎的pool_recycle默认值为 -1 ,这不需要任何连接回收。我只是将21 600(6小时)的值传递给 create_engine 函数,错误就消失了。
答案 2 :(得分:0)
sqlalchemy
提供了两种处理断开连接的方式,documentation
简短版本:
使用try...except
块来捕获断开连接异常。这将在失败的请求上返回500
,然后Web应用程序正常继续。如果不经常断开连接,请使用此方法。注意:您需要在try...except
块中包装每个可能的失败操作。
每次从池中签出连接时,基本上都会执行额外的ping
操作(类似SELECT 1
)。如果ping
失败引发DisconnectionError
,主机池将尝试强制创建新连接(事实上,池将在正式放弃之前尝试3次)。这样,您的应用程序就不会看到500
错误。权衡是执行的额外SQL,尽管根据文档,开销很小。