如何使用 Flask-SQLAlchemy 避免 QueuePool limit 错误?

How to avoid the QueuePool limit error using Flask-SQLAlchemy?

我正在使用 Flask-SQLAlchemy 和 Postgre DB 开发一个网络应用程序,然后我的网页中有这个下拉列表,在 selecting 之后从 select 填充到数据库几次不同的值我得到“sqlalchemy.exc.TimeoutError:”。

我的包的版本是:

Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.8.6
SQLAlchemy==1.4.15

我的数据库连接参数设置为:

app.config['SQLALCHEMY_POOL_SIZE'] = 20
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 5
app.config['SQLALCHEMY_POOL_RECYCLE'] = 10

我得到的错误是:

sqlalchemy.exc.TimeoutError: QueuePool limit of size 20 overflow 20 reached, connection timed out, timeout 5.00 (Background on this error at: https://sqlalche.me/e/14/3o7r)

将 'SQLALCHEMY_MAX_OVERFLOW' 的值从 20 更改为 100 后,下拉列表中的一些值发生更改后出现以下错误。

psycopg2.OperationalError: connection to server at "localhost" (::1), port 5432 failed: FATAL:  sorry, too many clients already

每次从下拉列表中 select 编辑一个新值时,都会触发对数据库的四个查询,它们用于将结果填充到我的 HTML 中的四个相应表中查询。

我在每次查询数据库后都有一个 'db.session.commit()' 语句,但即使我有它,在我的下拉列表的一些值更改后我也会收到此错误。

我知道我应该寻求正确管理我的连接会话,但我正在努力解决这个问题。我考虑过将池超时设置为 5 秒,而不是默认的 30 秒,希望以更快的方式关闭会话并返回池,但似乎没有帮助。

根据@snakecharmerb 的建议,我检查了以下输出:

select * from pg_stat_activity;

我 运行 webapp 有 10 个不同的值,然后它向我显示错误,这意味着所有 20+20 个会话都被使用并处于 'idle in transaction' 状态。

有人对我应该改变或寻找什么有什么想法建议吗?

您正在泄漏连接。

有点违反直觉, 您可能会发现使用 较低 池限制可以获得更好的结果。 一个给定的 python 线程只需要一个池连接, 对于您正在执行的简单的单数据库查询。 将限制设置为 10 溢出, 将使您更早地注意到泄漏的连接。 这使得更容易将责任归咎于泄露它的源代码。 就目前而言,您有很多代码,并且错误被推迟了 直到发出许多查询之后, 更难推理系统行为。 我假设您使用的是 sqlalchemy 1.4.29。

为避免泄漏,请尝试使用此方法:

from contextlib import closing
from sqlalchemy import create_engine, text
from sqlalchemy.orm import scoped_session, sessionmaker

engine = create_engine(some_url, future=True, pool_size=1, max_overflow=0)
get_session = scoped_session(sessionmaker(bind=engine))
...
with closing(get_session()) as session:
    try:
        sql = """yada yada"""
        rows = session.execute(text(sql)).fetchall()
        session.commit()
        ...
        # Do stuff with result rows.
        ...
    except Exception:
        session.rollback()

我在 Whosebug 的另一个 post 中找到了解决我所面临问题的方法。

当您将 Flask 应用程序分配给 db 变量时,除了指示它应该使用哪个 Flask 应用程序之外,您还可以传递会话选项,如下所示:

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app, session_options={'autocommit': True})

使用 'autocommit' 解决了我的问题。

现在,按照建议,我正在使用:

app.config['SQLALCHEMY_POOL_SIZE'] = 1
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 0

现在一切正常。

原来对我有帮助的post是:Autocommit in Flask-SQLAlchemy

@snakecharmerb,@jorzel,@J_H -> 感谢您的帮助!