提问人:Amin Ba 提问时间:12/18/2021 最后编辑:Amin Ba 更新时间:9/29/2022 访问量:11627
如何在 python 中运行 gunicorn 而不是作为命令行?
How to run gunicorn inside python not as a command line?
问:
我有一个烧瓶应用程序。
我使用以下命令在生产环境中运行它:
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()
答:
在my_file.py中插入以下内容
from subprocess import run
run("gunicorn -w 1 -b 0.0.0.0:5000 'path.to.wsgi:return_app()'".split(' '))
评论
这样的东西对我有用。
首先,我实例化 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)
评论
number_of_workers()
initialize()
我的目标并不完全相同:我可以将应用程序指定为字符串(与在命令行上使用 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 的启动方式与从命令行调用它时的方式基本相同。StandaloneApplication
app_uri
WsgiApplication
BaseApplication
注意:在 中,我有 .在 , 下 , 我有 - 所以我可以用 .我也在用 建造一个神器,所以我可以跑去启动 gunicorn。myproject/main.py
app = FastAPI()
pyproject.toml
[tool.poetry.scripts]
web = "myproject.web:run"
poetry run web
shiv -c web myproject.whl -o web.pyz
/path/to/web.pyz
评论