【问题标题】:How do I close a Flask-SQLAlchemy connection that I used in a Thread?如何关闭我在线程中使用的 Flask-SQLAlchemy 连接?
【发布时间】:2021-06-26 18:42:11
【问题描述】:

当我在线程中查询 Flask-SQLAlchemy 模型时,数据库连接似乎永远不会关闭。这是一个测试用例:

from threading import Thread
from sqlalchemy.pool import NullPool
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
db = SQLAlchemy()
app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///testdb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
    'poolclass': NullPool,
}
db.app = app
db.init_app(app)


class TestModel(db.Model):
    __tablename__ = "test_table"

    id = db.Column(db.Integer, autoincrement=True, primary_key=True)


@app.route('/test-connection')
def test_connection():
    def run_test():
        models = TestModel.query.all()
        print(models)
    thread = Thread(target=run_test)
    thread.start()
    return "OK"


app.run(debug=True, host='0.0.0.0')

当我运行我的路线时,它会在我的 pg_stat_activity 表中永久留下一个 idle in transaction 查询:

testdb=# select query, state from pg_stat_activity where query like '%test_table%' and query not like '%pg_stat_activity%';
                 query                  |        state        
----------------------------------------+---------------------
 SELECT test_table.id AS test_table_id +| idle in transaction
 FROM test_table                        | 
(1 row)

如果我同步调用run_test 函数而不是在线程中调用该行不会显示。在生产中,这会导致我的应用程序耗尽数据库连接并崩溃。在线程中使用后如何关闭我的 Flask-SQLAlchemy 数据库连接?

我正在使用 Python 3.8.6、SQLAlchemy 1.3.18 和 Flask-SQLAlchemy 2.4.4。

【问题讨论】:

    标签: python postgresql flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我们在打开连接时遇到了类似的问题。虽然有问题的数据库是 SQL Server,但我相信同样的解决方案应该在这里工作。

    我们添加了关闭数据库连接的方法。

    def cleanup(session):
        """
        This method cleans up the session object and closes the connection pool using the dispose 
        method.
        """
        session.close()
        engine_container.dispose()
    

    engine_container 定义为: engine_container = db.get_engine(app)

    我们在每次请求后从 finally 块中调用此方法。

    finally:
        cleanup(db.session)
    

    进行此更改后,您的代码应如下所示:

    from threading import Thread
    from sqlalchemy.pool import NullPool
    from flask_sqlalchemy import SQLAlchemy
    from flask import Flask
    
    db = SQLAlchemy()
    app = Flask(__name__)
    
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///testdb'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
        'poolclass': NullPool,
    }
    db.app = app
    db.init_app(app)
    engine_container = db.get_engine(app)
    
    
    class TestModel(db.Model):
        __tablename__ = "test_table"
    
        id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    
    
    @app.route('/test-connection')
    def test_connection():
        def run_test():
            try:
                models = TestModel.query.all()
                print(models)
            except Exception as err:
                raise err
            finally:
                cleanup(db.session)
    
        thread = Thread(target=run_test)
        thread.start()
        return "OK"
    
    
    def cleanup(session):
        """
        This method cleans up the session object and also closes the connection pool using the dispose method.
        """
        session.close()
        engine_container.dispose()
    
    
    app.run(debug=True, host='0.0.0.0')
    

    【讨论】:

      【解决方案2】:

      您遇到的问题与幕后发生的连接池有关。值得阅读的好资源可能是 SQLAlchemy resource 设置池回收参数,以及 SQLAlchemy resource 重置返回行为。

      SQLALCHEMY_ENGINE_OPTIONS = {
          pool_size=20,
          pool_reset_on_return='commit', # looks like postgres likes this more than rollback
          pool_timeout=5, # try a low value here maybe
      }
      

      看起来还有一些有用的信息here。创建一个在成功响应后基本上关闭会话连接的自定义函数可能会很有用。

      不幸的是,我自己并没有太多的 postgres 经验,不得不通过 MySQL 连接池来修补我的承诺之地。我想答案实际上会在 Postgres 文档中的某处找到,就像在我自己​​的 MySQL 文档中一样。

      【讨论】:

        猜你喜欢
        • 2015-07-28
        • 1970-01-01
        • 2019-12-28
        • 2015-05-16
        • 2015-09-11
        • 2021-09-03
        • 2016-12-05
        • 2019-03-30
        相关资源
        最近更新 更多