相关疑难解决方法(0)

无效的事务在请求之间保持不变

摘要

我们生产中的一个线程遇到了一个错误,现在正在产生InvalidRequestError: This session is in 'prepared' state; no further SQL can be emitted within this transaction.错误,每次请求都有一个查询它服务的余生!现在已经好几天了!这怎么可能,我们如何防止它向前发展?

背景

我们在uWSGI上使用Flask应用程序(4个进程,2个线程),Flask-SQLAlchemy为我们提供了与SQL Server的数据库连接.

当我们的一个生产线程正在拆除它的请求时,问题似乎开始了,在这个Flask-SQLAlchemy方法中:

@teardown
def shutdown_session(response_or_exc):
    if app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']:
        if response_or_exc is None:
            self.session.commit()
    self.session.remove()
    return response_or_exc
Run Code Online (Sandbox Code Playgroud)

...... self.session.commit()当事务无效时,以某种方式设法调用.这导致sqlalchemy.exc.InvalidRequestError: Can't reconnect until invalid transaction is rolled back输出到stdout,无视我们的日志记录配置,这是有道理的,因为它发生在应用程序上下文拆除期间,这从来不应该引发异常.我不确定如果没有response_or_exec设置,交易如何变得无效,但这实际上是AFAIK的较小问题.

更大的问题是,当"准备好的'状态"错误开始时,并且从那时起就没有停止过.每次这个线程提供命中数据库的请求时,它就是500s.每个其他线程似乎都没问题:据我所知,即使是在同一进程中的线程也没问题.

胡乱猜测

SQLAlchemy邮件列表中有一个关于"'准备好的'状态"错误的条目,说明如果会话开始提交但尚未完成,而其他东西试图使用它.我的猜测是,这个帖子中的会话永远不会self.session.remove()迈出这一步,现在它永远不会.

我仍然觉得这并没有解释这个会话如何在请求中持续存在.我们还没有修改Flask-SQLAlchemy对请求范围会话的使用,因此会话应该返回到SQLAlchemy的池并在请求结束时回滚,即使是错误的(尽管可能不是第一个,因为在应用程序上下文中引发的内容被拆除了).为什么回滚没有发生?如果我们每次都看到stdout上的"无效事务"错误(在uwsgi的日志中),我就能理解它,但我们不是:我第一次只看到它一次.但每次500秒发生时,我都会看到"准备好的状态"错误(在我们的应用程序日志中).

配置细节

我们已经关闭expire_on_commitsession_options,我们已经开启了SQLALCHEMY_COMMIT_ON_TEARDOWN.我们只是从数据库中读取,而不是写作.我们还使用Dogpile-Cache进行所有查询(使用memcached锁,因为我们有多个进程,实际上是2个负载均衡的服务器).缓存会在每分钟到期,因为我们的主要查询.

更新2014-04-28:解决步骤

重启服务器似乎已经解决了问题,这并不奇怪.也就是说,我希望能再次看到它,直到我们弄清楚如何阻止它.benselme(下面)建议编写我们自己的拆解回调,并在提交时进行异常处理,但我觉得更大的问题是该线程在其余生中被搞砸了.事实上,在一两个请求之后这并没有消失,这让我很紧张!

python sqlalchemy flask uwsgi flask-sqlalchemy

36
推荐指数
2
解决办法
1万
查看次数

标签 统计

flask ×1

flask-sqlalchemy ×1

python ×1

sqlalchemy ×1

uwsgi ×1