运行 带有 uWSGI 的烧瓶应用程序

Run flask application with uWSGI

我有一个 Flask 应用程序,我想 运行 使用 uwsgi 以“生产”方式使用它。

我有我的 launcher.py:

from app import app
import db

if __name__ == "__main__":
    db.init()
    app.run()

如果我 运行 应用程序只需 python launcher.py 就可以了。特别是 db.init() 被正确调用。

但是,如果我 运行 将 uwgsi 与 uwsgi app.ini 一起使用,则不会调用 db.init()

这里是app.ini:

[uwsgi]
wsgi-file = launcher.py
callable = app
socket = :8080

我是 flask 和 uwsgi 的新手,所以我可能错过了一些东西,但我在阅读的不同教程中找不到解决方案。

此外,如果您需要它来了解项目,这里是 app.py:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "hello from flask"

if __name__ == "__main__":
    db.init()
    app.run()

所有文件在我的项目中都处于同一级别:

webserver/
    - app.ini
    - launcher.py
    - app.py
    - db.py

那么,我做错了什么?

您在 if __name__ == "__main__": 下的代码未执行,因为 uwsgi 不像 python app.py 那样 运行 您的脚本。相反,它导入在 wsgi-file 中指定的模块并查找指定为 callable 的对象(在我们的例子中是应用程序)。您可以使用以下脚本对其进行测试:

from flask import Flask

app = Flask(__name__)

print(__name__)
if __name__ == '__main__':
    app.run()

如果你 运行 它与 python ./flask_app.py 那么输出将是

$ python ./flask_app.py
__main__
 * Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

(注意 __main__ - 这意味着我们正在 运行 脚本)。但是,如果你 运行 它与 uwsgi 一起 __name__ 将是 app (它将是你的文件的名称,所以在我的例子中是 app):

$ uwsgi --http 127.0.0.1:5000 --module app:app 
...
*** Operational MODE: single process ***
app
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7fb2d0c067b0 pid: 46794 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 46794, cores: 1)

如果您 运行 您的应用程序带有 FLASK_APP=app flask run,则会出现类似的输出 - 它不执行脚本,它只是导入脚本并使用其中的 app 对象。

因此,为了初始化数据库,您应该将数据库初始化移出 if __name__ == "__main__":

from flask import Flask

app = Flask(__name__)


class DB:
    def init(self):
        self.data = 'Hello, World'


db = DB()


@app.route("/")
def hello_world():
    return db.data


db.init()

if __name__ == '__main__':
    app.run()

或添加一个 before_first_request 处理程序:

# replace db.init() with 
@app.before_first_request
def init_db():
    db.init()

请注意它们之间的区别 - 如果您将 db.init() 作为 top-level 语句放置,它将在您加载 app.py 后执行。如果您注册一个 before_first_request 回调,它将在第一个请求到达您的应用程序时执行。选择最适合您的一款。