在mod_wsgi的Flask应用中保持状态

0 投票
2 回答
934 浏览
提问于 2025-04-18 11:10

我有一个Flask应用程序,它在mod_wsgi下运行,并且连接了一个数据库。这个应用程序有多个进程在运行(每个进程只有一个线程),每个进程都有一个数据库连接。

现在我的代码大概是这样的:

myapp_wsgi.py

import myapp
app = myapp.setup()

def application(environ, start_response):
    return app(environ, start_response)

myapp.py

from flask import Flask

app = Flask(__name__)

db = None

def setup():
    global db
    db = get_db()
    # Other setup
    return app

@app.route("/")
def index():
    data = db.get_data()
    return data

现在在这里使用全局变量让我感觉不太好。如果这个应用是一个类的话,我可以用 self.db 来处理,但它不是。有没有更好、更符合Python风格、更符合Flask风格的方法来做到这一点呢?

2 个回答

0

关于在wsgi线程之间共享状态,有一个指令可以放在apache的虚拟主机配置中,这样它们就可以在同一个上下文中执行。

WSGIApplicationGroup指令可以用来指定一个WSGI应用程序或一组WSGI应用程序属于哪个应用组。所有在同一个应用组中的WSGI应用程序都会在处理请求的进程的同一个Python子解释器的上下文中执行。

请注意,这个是针对同一个进程中的线程,而不是不同进程之间。

1

这主要取决于你使用的数据库和ORM(对象关系映射工具)。如果你使用的是SQLAlchemy或者flask-sqlalchemy(我强烈建议你使用这个),通常你会定义一个全局变量来连接数据库。这个连接一般是在一个叫做init_app()的函数中设置的。如果你查看应用程序的设置代码,你会发现主flask应用对象通常是一个全局变量app。而数据库对象通常也是一个全局变量db,它通常和app一起被导入到应用的其他部分。

你应该查看一下应用上下文请求上下文的文档,特别是上下文的局部性,它解释了这些是如何工作的。基本上,上下文在请求之间(也就是线程之间)是不会共享的,所以不会出现竞争条件和问题。

另外,在你的情况下,global这个关键字并不是必须的。因为你实际上不会改变db变量的内容。它是一个控制数据库连接的对象,你只需要调用它提供的方法。global关键字在你想要改变变量内容时才需要,比如给它赋一个新值。

所以,我会把setup()函数重构成这样(最好把它放在__init__.py中,这样更方便导入)

from flask import Flask

def setup():
    app = Flask(__name__)
    db = get_db() #This is a local variable now
    # whatever else needs to be done
    return app, db

app, db = setup()

然后在mod_wsgi.py中

from myapp import app

def application(environ, start_response):
    return app(environ, start_response)   

撰写回答