【发布时间】:2022-12-29 01:39:27
【问题描述】:
我有一个遗留的 Flask 项目,它现在有一些异步视图,它们也使用 Flask-SQLAlchemy 进行同步数据库调用。我的期望是这些将阻止调用,但它们应该可以正常工作。但是,我注意到当在异步视图中使用 Flask-SQLAlchemy 会话时,事务在数据库中被卡为“事务中空闲”。
可以通过运行以下示例代码来重现此问题:
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 块中发出 by the call to self.session.remove() on this line of code。我可以确认在每个异步视图结束时也调用了这一行,但它不会发出任何 SQL 或结束会话。
我的问题是:有没有办法让我在async Flask 视图中使用我现有的同步 Flask-SQLAlchemy 会话并让它正确关闭会话?
【问题讨论】:
标签: postgresql flask async-await sqlalchemy flask-sqlalchemy