如何正确设置 Flask + uWSGI + SQLAlchemy 以避免数据库连接问题

And*_*der 3 flask uwsgi flask-sqlalchemy

我正在使用带有 SQLAlchemy 的 Flask 应用程序和 uWSGI 服务器。一个已知问题是,uWSGI 在分叉期间通过所有进程重复连接。有关如何解决此问题的信息在网络上有点分散,但两个主要选项似乎是:

  • 在uWSGI的配置中使用lazy-apps = true(不推荐,因为它消耗大量内存)
  • 使用 uWSGI 的@postfork装饰器在分叉后关闭连接,为每个新进程启动新的连接,但我不清楚何时以及如何在 Flask 应用程序中使用。

这是我的应用程序的示例:

# file: my_app/app.py

db = SQLAlchemy()


def create_app():
    app = Flask(__name__)
    app.config.from_pyfile(f'../config/settings.py')
    db.init_app(app)
    db.create_all(app=app)
    return app
Run Code Online (Sandbox Code Playgroud)

run.py文件示例:

# file: run.py
from my_app/app import create_app


app = create_app()
if "__main__" == __name__:
    app.run(debug=app.config["DEBUG"], port=5000)
Run Code Online (Sandbox Code Playgroud)

所以问题是 postfork 应该在哪里以及如何执行来正确设置 uWSGI 的服务器以在每个进程上使用隔离连接而不使用lazy-apps = true

小智 7

SQLAlchemy 手册提供了两个如何解决此问题的示例:Using Connection Pools with Multiprocessing

第一种涉及的方法Engine.dispose()可以使用 Hett 建议的方法来实现uwsgidecorators.postfork- 如果仅涉及默认绑定,则简单的示例应该有效:

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "postgres:///test"
    db.init_app(app)

    def _dispose_db_pool():
        with app.app_context():
            db.engine.dispose()

    try:
        from uwsgidecorators import postfork
        postfork(_dispose_db_pool)
    except ImportError:
        # Implement fallback when running outside of uwsgi...
        raise

    return app
Run Code Online (Sandbox Code Playgroud)

第二个涉及sqlalchemy.event并丢弃来自不同 PID 的连接 - 引用:

下一个方法是使用事件来检测池本身,以便连接在子流程中自动失效。这有点神奇,但可能更万无一失。

如果您想要后一种神奇的解决方案,请参阅文档。