简体   繁体   English

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

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

I'm developing a webapp using Flask-SQLAlchemy and a Postgre DB, then I have this dropdown list in my webpage which is populated from a select to the DB, after selecting different values for a couple of times I get the "sqlalchemy.exc.TimeoutError:".我正在使用 Flask-SQLAlchemy 和 Postgre DB 开发一个 webapp,然后我的网页中有这个下拉列表,该下拉列表从 select 填充到 DB,在选择不同的值几次后,我得到“sqlalchemy.exc .TimeoutError:"。

My package's versions are:我的包的版本是:

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

My parameters for the DB connection are set as:我的数据库连接参数设置为:

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

The error I'm getting is:我得到的错误是:

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)

After changing the value of the 'SQLALCHEMY_MAX_OVERFLOW' from 20 to 100 I get the following error after some value changes on the dropdown list.将“SQLALCHEMY_MAX_OVERFLOW”的值从 20 更改为 100 后,下拉列表中的一些值更改后出现以下错误。

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

Every time a new value is selected from the dropdown list, four queries are triggered to the database and they are used to populate four corresponding tables in my HTML with the results from that query.每次从下拉列表中选择一个新值时,都会触发对数据库的四个查询,它们用于使用该查询的结果填充我的 HTML 中的四个相应表。

I have a 'db.session.commit()' statement after every single query to the DB, but even though I have it, I get this error after a few value changes to my dropdown list.在对数据库的每个查询之后,我都有一个“db.session.commit()”语句,但即使我有它,在对我的下拉列表进行一些值更改后,我也会收到此错误。

I know that I should be looking to correctly manage my connection sessions, but I'm strugling with this.我知道我应该寻求正确管理我的连接会话,但我正在为此苦苦挣扎。 I thought about setting the pool timeout to 5s, instead of the default 30s in hopes that the session would be closed and returned to the pool in a faster way, but it seems it didn't help.我考虑过将池超时设置为 5 秒,而不是默认的 30 秒,希望 session 能够以更快的方式关闭并返回到池中,但似乎没有帮助。

As a suggestion from @snakecharmerb, I checked the output of:作为@snakecharmerb 的建议,我检查了 output 的:

select * from pg_stat_activity;

I ran the webapp for 10 different values before it showed me an error, which means all the 20+20 sessions where used and are left in an 'idle in transaction' state.在它向我显示错误之前,我运行了 10 个不同的值的 webapp,这意味着所有使用的 20+20 个会话都处于“事务空闲”state 中。

Do anybody have any idea suggestion on what should I change or look for?有人对我应该改变或寻找什么有任何想法建议吗?

You are leaking connections.您正在泄漏连接。

A little counter intuitively, you may find you obtain better results with a lower pool limit.有点反直觉,您可能会发现使用较低的池限制获得更好的结果。 A given python thread only needs a single pooled connection, for the simple single-database queries you're doing.对于您正在执行的简单单数据库查询,给定的 python 线程只需要一个池连接。 Setting limit to 1 , with 0 overflow, will cause you to notice a leaked connection earlier.将 limit 设置为1 ,溢出0会导致您更早地注意到泄漏的连接。 This makes it easier to pin blame on the source code that leaked it.这使得更容易将责任归咎于泄露它的源代码。 As it stands, you have lots of code and the error is deferred until after a bunch of queries have been issued, making it harder to reason about system behavior.就目前而言,您有很多代码,并且错误会延迟到发出一堆查询之后,这使得推理系统行为变得更加困难。 I will assume you're using sqlalchemy 1.4.29.我假设您使用的是 sqlalchemy 1.4.29。

To avoid leaking, try using this:为避免泄漏,请尝试使用以下方法:

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()

I found a solution to the issue I was facing, in another post from StackOverFlow.我在 StackOverFlow 的另一篇文章中找到了解决我所面临问题的方法。

When you assign your flask app to your db variable, on top of indicating which Flask app it should use, you can also pass on session options, as below:当您将 flask 应用程序分配给您的 db 变量时,除了指示它应该使用哪个 Flask 应用程序之外,您还可以传递 session 选项,如下所示:

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

The usage of 'autocommit' solved my issue. 'autocommit' 的使用解决了我的问题。

Now, as suggested, I'm using:现在,正如建议的那样,我正在使用:

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

Now everything is working as it should.现在一切正常。

The original post which helped me is: Autocommit in Flask-SQLAlchemy对我有帮助的原始帖子是: Autocommit in Flask-SQLAlchemy

@snakecharmerb, @jorzel, @J_H -> Thanks for the help! @snakecharmerb、@jorzel、@J_H -> 感谢您的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM