我正在将Flask应用程序与SQLAlchemy和uWSGI服务器一起使用。一个众所周知的问题是,uWSGI在分叉期间通过所有过程复制了连接。网络上有些关于如何解决此问题的信息,但是似乎有两个主要选项:
lazy-apps = true
(不推荐使用,因为它会占用大量内存)@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.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)
所以问题是执行postfork的位置和方式如何正确设置uWSGI的服务器以在每个进程上使用隔离的连接而不使用lazy-apps = true
?
通常,您需要使用uwsgi提供的@postfork装饰器。我们没有使用SQLAlchemy,但我认为您也可以根据情况调整我们的解决方案。
这是我们的uwsgi配置的摘录:
[uwsgi]
strict = true
; process management
master = true
vacuum = true
pidfile = /tmp/uwsgi.pid
enable-threads = true
cpu-affinity = 1
processes = 4
threads = 2
mules = 2
...
这是使用@postfork创建进程安全的数据库连接的应用程序初始化代码。
from flask import Flask
from uwsgidecorators import postfork
from app.lib.db import DB # DB object will be replaced by SQLAlchemy on your side
app = Flask(__name__)
# due to uwsgi's copy-on-write semantics workers need to connect to database
# to preserve unique descriptors after fork() is called in master process
@postfork
def db_reconnect():
# Open the DB connection and log the event
app.db = DB(config.get('db', 'host'),
config.get('db', 'user'),
config.get('db', 'pass'),
config.get('db', 'name'))
在我们的情况下,所有初始化代码都放在__init__.py
或app
文件夹中,但我认为将其迁移到app.py
文件中不会有任何困难。
让我知道您是否还会遇到其他问题。