使用Flask-SQLAlchemy和异步Flask视图时的“事务空闲”PostgreSQL查询

eufgjt7s  于 2022-12-29  发布在  PostgreSQL
关注(0)|答案(1)|浏览(214)

我有一个遗留的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会话,并让它正确地关闭会话?

col17t5w

col17t5w1#

这是Flask-SQLAlchemy中的一个错误,已在版本3.0.0中修复

相关问题