我有一个遗留的Flask项目,现在有一些异步视图,也使用Flask-SQLAlchemy进行同步数据库调用。我的期望是这些视图将阻塞调用,但它们应该工作正常。然而,我注意到当Flask-SQLAlchemy会话用于异步视图时,事务在数据库中被卡住为"idle in transaction"。
通过运行以下示例代码可以重现此问题:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://127.0.0.1:5432/temp"
app.config["SQLALCHEMY_ECHO"] = True
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
class SomeModel(db.Model):
"""Simplest possible model."""
id = db.Column(db.Integer, primary_key=True)
@app.route("/async")
async def hello_async():
"""Sample asynchronous view."""
SomeModel.query.all()
return "Hello"
@app.route("/sync")
def hello_sync():
"""Sample synchronous view."""
SomeModel.query.all()
return "Hello"
if __name__ == "__main__":
db.create_all()
app.run()
加载/sync
端点时,终端输出如下所示:
2022-09-26 09:28:21,300 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-09-26 09:28:21,300 INFO sqlalchemy.engine.Engine SELECT some_model.id AS some_model_id
FROM some_model
2022-09-26 09:28:21,300 INFO sqlalchemy.engine.Engine [cached since 15.05s ago] {}
2022-09-26 09:28:21,303 INFO sqlalchemy.engine.Engine ROLLBACK
127.0.0.1 - - [26/Sep/2022 09:28:21] "GET /sync HTTP/1.1" 200 -
但是,当访问/async端点时,我看到:
2022-09-26 09:28:46,277 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-09-26 09:28:46,277 INFO sqlalchemy.engine.Engine SELECT some_model.id AS some_model_id
FROM some_model
2022-09-26 09:28:46,277 INFO sqlalchemy.engine.Engine [cached since 40.03s ago] {}
127.0.0.1 - - [26/Sep/2022 09:28:46] "GET /async HTTP/1.1" 200 -
注意,第二组日志缺少同步版本中发出的INFO sqlalchemy.engine.Engine ROLLBACK
。因此,如果我使用以下命令查询Postgres:
select query, state from pg_stat_activity where state = 'idle in transaction'
我将看到一个空闲的查询,我已经作出了异步端点的每一个请求。如果我作出额外的请求/async
端点,这些查询将最终饱和SQLAlchemy连接池,导致TimeoutError: QueuePool limit
错误和应用程序将500.
通过查看Flask-SQLAlchemy源代码,我可以看到ROLLBACK
通常是由@app.teardown_appcontext
块中这一行代码上对self.session.remove()
的调用发出的,我可以确认这一行也在每个异步视图的末尾被调用,但它不发出任何SQL或结束会话。
我的问题是:有没有办法在async
Flask视图中使用现有的同步Flask-SQLAlchemy会话,并让它正确地关闭会话?
1条答案
按热度按时间col17t5w1#
这是Flask-SQLAlchemy中的一个错误,已在版本3.0.0中修复