我正在使用Flask和Postgre开发一个get应用程序,然后在我的网页中有一个下拉列表,它是从select到DB填充的,在选择了几次不同的值之后,我得到了"sqlalchemy.exc.TimeoutError:“。
我的包裹的版本如下:
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.8.6
SQLAlchemy==1.4.15
我的DB连接参数设置为:
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
每次从下拉列表中选择一个新值时,都会向数据库触发四个查询,并使用它们在我的HTML中填充四个对应的表,其中包含来自该查询的结果。
在对DB的每个查询之后,我都有一个'db.session.commit()‘语句,但是即使我有它,在对我的下拉列表进行一些值更改之后,我也会得到这个错误。
我知道我应该正确地管理我的连接会话,但我对此很不放心。我考虑将池超时设置为5s,而不是默认的30秒,希望会话将以更快的方式关闭并返回池,但这似乎没有帮助。
作为@snakecharmerb的建议,我检查了以下内容的输出:
select * from pg_stat_activity;
在webapp显示错误之前,我运行了10个不同的值,这意味着使用的所有20+20会话都处于“空闲事务”状态。
有没有人知道我该换什么或找什么?
发布于 2022-01-10 12:13:05
在StackOverFlow的另一篇文章中,我找到了解决我所面临的问题的方法。
当您将烧瓶应用程序分配给db变量时,在指示应该使用哪个flask应用程序的基础上,您还可以传递会话选项,如下所示:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app, session_options={'autocommit': True})
“自动提交”的用法解决了我的问题。
现在,正如建议的那样,我正在使用:
app.config['SQLALCHEMY_POOL_SIZE'] = 1
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 0
现在一切都正常运转了。
帮助我的最初的帖子是:Autocommit in Flask-SQLAlchemy
@snakecharmerb,@jorzel,@J_H ->,谢谢你的帮助!
发布于 2022-01-08 18:07:41
你在泄露连接。
稍微有点反直觉,你可能会发现你得到了更好的结果与较低的池限制。对于您正在执行的简单的单数据库查询,给定的python线程只需要一个池连接。将限制设置为1
,加上0
溢出,将导致您更早地注意到一个泄漏的连接。这使我们更容易将责任归咎于泄露它的源代码。目前,您有大量的代码,并且错误被推迟到发出了许多查询之后,这使得对系统行为的推理变得更加困难。我假设您使用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()
发布于 2022-11-04 08:23:55
我用的是烧瓶-restful。因此,当我得到大小为20溢出20的-> QueuePool限制时,连接超时,超时5.00 (此错误的背景为:https://sqlalche.me/e/14/3o7r)
我在日志中发现我的已检出的连接没有关闭。这是我用logger.info(db_session.get_bind().pool.status())发现的
def custom_decorator(error_message, db_session):
def api_decorator(func):
def api_request(self, *args, **kwargs):
try:
response = func(self)
db_session.commit()
return response
except Exception as err:
db_session.rollback()
logger.error(error_message.format(err))
return error_response(
message=f"Internal Server Error",
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
)
finally:
db_session.close()
return api_request
return api_decorator
因此,我不得不创建这个装饰器,它自动处理db_session关闭。使用这一点,我不会得到任何主动检查的连接。
您可以在您的功能中使用装饰器,如下所示:
@custom_decorator("blah", db_session)
def example():
"some code"
https://stackoverflow.com/questions/70625689
复制相似问题