如何在Flask+uWSGI中设置自动重载?

37
8个回答

64

我正在运行uwsgi版本1.9.5并使用该选项

uwsgi --py-autoreload 1

运行得很好


1
使用uwsgi emperor模式,无法启动emperor进程或单独的应用程序ini配置。前者会提示“未知选项”,后者则没有任何提示。无论哪种方式,都必须重新启动进程才能注意到更改... - Zayne S Halsall
我该如何运行uwsgi --py-autoreload 1? - Burf2000
realpath() 函数 --py-autoreload=1 失败:没有这个文件或目录 [core/utils.c 第 3651 行] - AlxVallejo

36

如果你正在使用命令行参数配置uwsgi,请添加--py-autoreload=1

uwsgi --py-autoreload=1

如果您正在使用一个 .ini 文件来配置 uwsgi 并使用 uwsgi --ini,请将以下内容添加到您的 .ini 文件中:

py-autoreload = 1

1
文档:https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html 和 https://uwsgi-docs.readthedocs.io/en/latest/Options.html?highlight=py-autoreload#py-auto-reload - con-f-use

14

对于开发环境,你可以尝试使用uwsgi参数--python-autoreload。 从源代码来看,它可能只在线程模式(--enable-threads)下工作。


9
这个方法对我有效。将 python-autoreload = 1 添加到我的 uwsgi.ini 文件中即可重新加载!谢谢! - JoshFinnie
1
使用uwsgi emperor模式 - 这可以通过将其添加到应用程序的ini文件中来实现。谢谢! - Zayne S Halsall
1
我认为值得注意的是,这里的值 1true 不能 互换。只有 1 对我有效。 - kungphu
1
@kungphu 再次阅读文档,它说当启用时,它会启动一个线程来扫描更改。您设置的值是它执行扫描的间隔时间。 - Adam Ritter
1
@AdamRitter 我不小心链接了两次代码片段。代码片段 中提到了 py-autoreload,但文档中没有。而且,这不是被问及的属性,应该是 python-autoreload。实际文档中有几个选项看起来是相同的,包括这两个,尽管它们没有标记为别名。这有点令人困惑,而且无论如何,描述都不清楚。如果我确切地知道发生了什么,我会提交一个文档补丁。 - kungphu
显示剩余2条评论

8
您可以尝试使用supervisord作为Uwsgi应用程序的管理器。它还具有监视功能,当文件或文件夹被“触摸”/修改时,自动重新加载进程。
您可以在此处找到一个不错的教程: Flask+NginX+Uwsgi+Supervisord。链接为:Flask+NginX+Uwsgi+Supervisord

2
链接已不再可用。 - ricosrealm
1
已存档:https://web.archive.org/web/20120924045956/http://www.readncode.com:80/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/ - Florian
可疑的链接? - TheRealFakeNews

6
开发模式下 Flask 的自动重新加载功能实际上是由底层的 Werkzeug 库提供的。相关代码在 werkzeug/serving.py 中,值得一看。但基本上,主应用程序将 WSGI 服务器作为子进程生成,每秒钟检查一次每个活动的 .py 文件的状态,以查找更改。如果发现有更改,则子进程退出,父进程再次启动它 - 实际上重新加载更改。
在 uWSGI 层面上,您也可以实现类似的技术。如果您不想使用状态循环,可以尝试使用底层的操作系统文件监视命令。显然(根据 Werkzeug 的代码),pyinotify 存在漏洞,但是也许 Watchdog 能够工作?尝试几个方法,看看会发生什么。
编辑:针对评论,我认为这很容易重新实现。结合您链接中提供的示例以及来自 werkzeug/serving.py 的代码:
""" NOTE: _iter_module_files() and check_for_modifications() are both
    copied from Werkzeug code. Include appropriate attribution if
    actually used in a project. """
import uwsgi
from uwsgidecorators import timer

import sys
import os

def _iter_module_files():
    for module in sys.modules.values():
        filename = getattr(module, '__file__', None)
        if filename:
            old = None
            while not os.path.isfile(filename):
                old = filename
                filename = os.path.dirname(filename)
                if filename == old:
                    break
            else:
                if filename[-4:] in ('.pyc', '.pyo'):
                    filename = filename[:-1]
                yield filename

@timer(3)
def check_for_modifications():
    # Function-static variable... you could make this global, or whatever
    mtimes = check_for_modifications.mtimes
    for filename in _iter_module_files():
        try:
            mtime = os.stat(filename).st_mtime
        except OSError:
            continue

        old_time = mtimes.get(filename)
        if old_time is None:
            mtimes[filename] = mtime
            continue
        elif mtime > old_time:
            uwsgi.reload()
            return

check_for_modifications.mtimes = {} # init static

这是未经测试的,但应该可以工作。


谢谢你的建议!我已经稍微查看了werkzeug.serving,但是希望能够避免亲自动手,寻求一个快速的解决方案...也许现在是时候有人来实现它了。 :) - Florian

-1
在 .ini 文件中设置 py-autoreload=1 即可完成此任务。

-2
import gevent.wsgi
import werkzeug.serving

@werkzeug.serving.run_with_reloader
def runServer():
    gevent.wsgi.WSGIServer(('', 5000), app).serve_forever()

(您可以使用任意WSGI服务器)


3
很抱歉,这不是对我的问题的回答。我希望使用uwsgi进行服务。顺便说一句:Flask的app.run(debug=True)默认提供重新加载功能。 - Florian
虽然 Flask 自带的开发 Web 服务器提供了重新加载功能,但它也提供了一个用于调试的 shell!你可不想在生产环境中给每个人都提供 Python shell! - Jabba

-3

我担心Flask太基础了,无法默认捆绑此类实现。

在生产中动态重新加载代码通常是不好的事情,但如果您担心开发环境,请查看此bash shell脚本http://aplawrence.com/Unixart/watchdir.html

只需将睡眠间隔更改为适合您需求的值,并用您用于重新加载uwsgi的命令替换echo命令。我在master模式下运行uwsgi,只需发送killall uwsgi命令即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接