如何在 python 中运行 gunicorn 而不是作为命令行?

How to run gunicorn inside python not as a command line?

提问人:Amin Ba 提问时间:12/18/2021 最后编辑:Amin Ba 更新时间:9/29/2022 访问量:11627

问:

我有一个烧瓶应用程序。

我使用以下命令在生产环境中运行它:

python -m gunicorn -w 1 -b 0.0.0.0:5000 "path.to.wsgi:return_app()"

相反,我想在my_file.py中运行它

我需要一个函数来运行,它应该接受应用程序对象和端口绑定以及工作线程的数量

我该怎么做?

我需要像这个 psudo 代码这样的东西:

import gunicorn

app = return_app()

gunicorn(workers=1, ip="0.0.0.0", port=5000, app=app)

对我来说,最重要的部分是部分app=app

重点是我想将 app 对象用作 Flask() 的实例。我想直接将应用程序对象提供给 gunicorn,而不是在字符串中寻址它

我尝试过什么:我已经打开了 gunicorn 库 main.py 文件

from gunicorn.app.wsgiapp import run
run()

看看它是如何工作的,但无法弄清楚

def run():
    """\
    The ``gunicorn`` command line runner for launching Gunicorn with
    generic WSGI applications.
    """
    from gunicorn.app.wsgiapp import WSGIApplication
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
蟒蛇 烧瓶 Gunicorn

评论


答:

-3赞 Narcisse DOUDIEU SIEWE 12/18/2021 #1

在my_file.py中插入以下内容

from subprocess import run
run("gunicorn -w 1 -b 0.0.0.0:5000 'path.to.wsgi:return_app()'".split(' '))

评论

2赞 Amin Ba 12/18/2021
但我需要直接将应用程序作为 python 对象而不是字符串提供给它。
0赞 Amin Ba 12/18/2021
它仍然有局限性。我的想法是,如果我在 python 中运行它,我应该能够直接将应用程序提供给它。因为 Gunicorn 需要应用程序,而 Gunicorn 是 Python libarray。我应该能够在 python 中使用它
0赞 Narcisse DOUDIEU SIEWE 12/18/2021
run(“gunicorn -w 1 -b 0.0.0.0:5000 module_projet.wsgi”.split(' '), cwd=path_to_wsgi)
0赞 Narcisse DOUDIEU SIEWE 12/18/2021
@Amin Ba 是不是 django 应用程序?
0赞 Amin Ba 12/18/2021
看看我添加的代码
9赞 Zaero Divide 5/10/2022 #2

这样的东西对我有用。 首先,我实例化 BaseApplication 类。 它有一个方法。 有关如何在 gunicorn 文档中创建自定义应用程序的详细信息。run()

if platform.uname().system.lower()=='linux':
    print("Detected Linux, Preparing gunicorn")        
    import gunicorn.app.base
    class StandaloneApplication(gunicorn.app.base.BaseApplication):

        def __init__(self, app, options=None):
            self.options = options or {}
            self.application = app
            super().__init__()

        def load_config(self):
            config = {key: value for key, value in self.options.items()
                    if key in self.cfg.settings and value is not None}
            for key, value in config.items():
                self.cfg.set(key.lower(), value)

        def load(self):
            return self.application

if __name__ == "__main__":
    # Use a debugging session in port 5001    
    if platform.uname().system.lower()=='linux':
        print("Detected Linux, Running Gunicorn")
        options = {
            'bind': '%s:%s' % ('0.0.0.0', '5001'),
            'workers': number_of_workers(),
            # 'threads': number_of_workers(),
            'timeout': 120,
        }
        initialize()
        StandaloneApplication(app, options).run()
    else:
        print("Detected non Linux, Running in pure Flask")
        initialize()
        app.run(debug=True, host=socket.gethostbyname(socket.gethostname()), port=5001)

评论

2赞 Someone2 1/27/2023
您的 MWE 并不真正完整。例如: 还有一些人失踪了。如果你能完成它,那就太好了,这样你就可以独立运行它了。number_of_workers()initialize()
7赞 Jaza 9/29/2022 #3

我的目标并不完全相同:我可以将应用程序指定为字符串(与在命令行上使用 gunicorn 相同)而不是传递 python 应用程序对象。实际上,我不确定传递单个应用程序对象是否真的有意义,因为 gunicorn 不应该在它生成的每个工作线程中都有不同的应用程序对象吗?

我主要担心的是我在没有类似帮助或类似帮助的情况下运行 gunicorn。我还使用了 FastAPI 而不是 Flask,并且(根据当前推荐的 prod FastAPI 设置)告诉 gunicorn 生成 uvicorn 工人。subprocess

这就是我最终选择的(在):myproject/web.py

import multiprocessing

from gunicorn.app.wsgiapp import WSGIApplication


class StandaloneApplication(WSGIApplication):
    def __init__(self, app_uri, options=None):
        self.options = options or {}
        self.app_uri = app_uri
        super().__init__()

    def load_config(self):
        config = {
            key: value
            for key, value in self.options.items()
            if key in self.cfg.settings and value is not None
        }
        for key, value in config.items():
            self.cfg.set(key.lower(), value)


def run():
    options = {
        "bind": "0.0.0.0:8000",
        "workers": (multiprocessing.cpu_count() * 2) + 1,
        "worker_class": "uvicorn.workers.UvicornWorker",
    }
    StandaloneApplication("myproject.main:app", options).run()

My 与 Zaero Divide 在此线程中的答案非常相似(并且基于)。但是,我传递了 ,并且我继承了 而不是 ,这导致 gunicorn 的启动方式与从命令行调用它时的方式基本相同。StandaloneApplicationapp_uriWsgiApplicationBaseApplication

注意:在 中,我有 .在 , 下 , 我有 - 所以我可以用 .我也在用 建造一个神器,所以我可以跑去启动 gunicorn。myproject/main.pyapp = FastAPI()pyproject.toml[tool.poetry.scripts]web = "myproject.web:run"poetry run webshiv -c web myproject.whl -o web.pyz/path/to/web.pyz