如何使用 Flask-Script 和 Gunicorn
Posted
技术标签:
【中文标题】如何使用 Flask-Script 和 Gunicorn【英文标题】:How to use Flask-Script and Gunicorn 【发布时间】:2013-01-12 01:25:15 【问题描述】:我正在使用 Flask 的内置开发服务器开发 Flask 应用程序。我使用 Flask-Script 启动它。我想切换到使用 Gunicorn 作为 Web 服务器。为此,我是否需要在 Flask-Script 和 Gunicorn 之间编写某种集成代码?还是 Flask-Script 与使用 Gunicorn 运行应用程序无关?
提前致谢!
@sean-lynch 的道具。以下是根据他的回答工作的、经过测试的代码。 我所做的更改是:
在尝试启动服务器之前,从 sys.argv
中的 remove_non_gunicorn_command_line_args()
中删除 Gunicorn 无法识别的选项。否则 Gunicorn 会抛出错误,并显示如下消息:error: unrecognized arguments: --port 5010
。我删除了-p
,因为即使它不会导致错误,那只是因为 Gunicorn 认为它是其pidfile
选项的缩写形式,这显然不是预期的。
修改 GunicornServer.handle() 签名以匹配它覆盖的方法,即 Command.handle()
-
from flask_script import Command
from gunicorn.app.base import Application
class GunicornServer(Command):
description = 'Run the app within Gunicorn'
def __init__(self, host='127.0.0.1', port=8000, workers=6):
self.port = port
self.host = host
self.workers = workers
def get_options(self):
return (
Option('-t', '--host',
dest='host',
default=self.host),
Option('-p', '--port',
dest='port',
type=int,
default=self.port),
Option('-w', '--workers',
dest='workers',
type=int,
default=self.workers),
)
def handle(self, app, *args, **kwargs):
host = kwargs['host']
port = kwargs['port']
workers = kwargs['workers']
def remove_non_gunicorn_command_line_args():
import sys
args_to_remove = ['--port','-p']
def args_filter(name_or_value):
keep = not args_to_remove.count(name_or_value)
if keep:
previous = sys.argv[sys.argv.index(name_or_value) - 1]
keep = not args_to_remove.count(previous)
return keep
sys.argv = filter(args_filter, sys.argv)
remove_non_gunicorn_command_line_args()
from gunicorn import version_info
if version_info < (0, 9, 0):
from gunicorn.arbiter import Arbiter
from gunicorn.config import Config
arbiter = Arbiter(Config('bind': "%s:%d" % (host, int(port)),'workers': workers), app)
arbiter.run()
else:
class FlaskApplication(Application):
def init(self, parser, opts, args):
return
'bind': '0:1'.format(host, port),
'workers': workers
def load(self):
return app
FlaskApplication().run()
manager.add_command('gunicorn', GunicornServer())
【问题讨论】:
我认为这会更容易,在你的环境中安装 gunicorn,然后你可以创建一个 gunicorn.conf 文件,你可以在其中声明 gunicorn 配置(工人数量,绑定端口,pid,等等...),然后调用 gunicorn -c gunicorn.conf runserver:app (yourrunappfile:yourapp variable) 【参考方案1】:Flask 实际上有运行 Gunicorn here 的文档。
你必须记住 Gunicorn 是一个有一些细节的 WSGI 服务器。
【讨论】:
如果您使用的是flask_script,那将无济于事。问题仍然存在,您需要传递其他参数。【参考方案2】:正如 Dhaivat 所说,您可以直接将 Flask 应用程序与 Gunicorn 一起使用。
如果您仍想使用 Flask-Script,则需要创建自定义 Command
。我没有任何使用 Gunicorn 的经验,但我为 Flask-Actions 找到了类似的 solution 并将其移植到 Flask-Script,但请注意,它未经测试。
from flask_script import Command, Option
class GunicornServer(Command):
description = 'Run the app within Gunicorn'
def __init__(self, host='127.0.0.1', port=8000, workers=4):
self.port = port
self.host = host
self.workers = workers
def get_options(self):
return (
Option('-H', '--host',
dest='host',
default=self.host),
Option('-p', '--port',
dest='port',
type=int,
default=self.port),
Option('-w', '--workers',
dest='workers',
type=int,
default=self.workers),
)
def handle(self, app, host, port, workers):
from gunicorn import version_info
if version_info < (0, 9, 0):
from gunicorn.arbiter import Arbiter
from gunicorn.config import Config
arbiter = Arbiter(Config('bind': "%s:%d" % (host, int(port)),'workers': workers), app)
arbiter.run()
else:
from gunicorn.app.base import Application
class FlaskApplication(Application):
def init(self, parser, opts, args):
return
'bind': '0:1'.format(host, port),
'workers': workers
def load(self):
return app
FlaskApplication().run()
然后您可以注册它以替换 Flask 的 local development server python manage.py runserver
manager.add_command("runserver", GunicornServer())
或注册为新命令,如python manage.py gunicorn
manager.add_command("gunicorn", GunicornServer())
2016 年 6 月编辑:使用最新版本的 Flask-Script,将方法 handle
更改为 __call__
。 old flask-script 与 new flask-script
【讨论】:
还没有。但这足以为我指明正确的方向。如果我发现我需要对您提供的代码进行更改,我会在这里发布。 按承诺发布。再次感谢您的帮助。 这是我的错误报告:TypeError: <gunicorn.Gunicorn object at 0x7f15bb51ef90>: run() got an unexpected keyword argument 'host'
我收到以下错误:TypeError: <__main__.GunicornServer object at 0x106a084d0>: __call__() got an unexpected keyword argument 'proxy_protocol'
你好,我想问一下如何将这个链接到运行guincorn的方式为linux service?【参考方案3】:
我在 Sean Lynch 的基础上写了一个更好的 GunicornServer 版本,该命令现在接受所有 gunicorn 的参数
from yourapp import app
from flask.ext.script import Manager, Command, Option
class GunicornServer(Command):
"""Run the app within Gunicorn"""
def get_options(self):
from gunicorn.config import make_settings
settings = make_settings()
options = (
Option(*klass.cli, action=klass.action)
for setting, klass in settings.iteritems() if klass.cli
)
return options
def run(self, *args, **kwargs):
from gunicorn.app.wsgiapp import WSGIApplication
app = WSGIApplication()
app.app_uri = 'manage:app'
return app.run()
manager = Manager(app)
manager.add_command("gunicorn", GunicornServer())
【讨论】:
@sholsapp 事实上,--reload
在使用 gunicorn 时不会像预期的那样工作。我重写 GunicornServer gist.github.com/menghan/9a632bbb0acb445f4f3a【参考方案4】:
根据肖恩的回答,我也写了一个更适合我的版本。
@manager.option('-h', '--host', dest='host', default='127.0.0.1')
@manager.option('-p', '--port', dest='port', type=int, default=6969)
@manager.option('-w', '--workers', dest='workers', type=int, default=3)
def gunicorn(host, port, workers):
"""Start the Server with Gunicorn"""
from gunicorn.app.base import Application
class FlaskApplication(Application):
def init(self, parser, opts, args):
return
'bind': '0:1'.format(host, port),
'workers': workers
def load(self):
return app
application = FlaskApplication()
return application.run()
你可以使用类似这样的命令运行 gunicornpython manager.py gunicorn
【讨论】:
我在运行命令时没有看到任何错误,但是我看不到任何服务器在 127.0.0.1:6969 上运行。上面的自定义命令对你有用吗?还是未经测试?【参考方案5】:我将进一步详细说明@NinjaDQ 的答案。如果您想同时使用app_uri
属性来定义例如flask 应用程序配置文件和自定义命令行参数,您需要使用WSGIApplication
。问题是这个应用程序overrides
是命令行参数,因此有必要忽略sys.argv
。
from gunicorn.app.base import Application
class FlaskApplication(Application):
def init(self, parser, opts, args):
return
"bind": "0:1".format(host, port),
"workers": 4
def chdir(self):
# chdir to the configured path before loading,
# default is the current dir
os.chdir(self.cfg.chdir)
# add the path to sys.path
sys.path.insert(0, self.cfg.chdir)
def load_wsgiapp(self):
self.chdir()
# load the app
return util.import_app(self.app_uri)
def load(self):
return self.load_wsgiapp()
# Important! Do not pass any cmd line arguments to gunicorn
sys.argv = sys.argv[:2]
wsgi_app = FlaskApplication()
wsgi_app.app_uri = "manage:create_app('0')".format(config_file)
return wsgi_app.run()
【讨论】:
【参考方案6】:根据 menghan 的回答,从 Application config 中接收所有参数。
from flask_script import Command, Option
class GunicornApp(Command):
def get_options(self):
from gunicorn.config import make_settings
settings = make_settings()
options = (
Option(*klass.cli, dest=klass.name, default=klass.default)
for setting, klass in settings.items() if klass.cli
)
return options
def __call__(self, app=None, *args, **kwargs):
from gunicorn.app.base import Application
class FlaskApplication(Application):
def init(self, parser, opts, args):
return kwargs
def load(self):
return app
FlaskApplication().run()
【讨论】:
【参考方案7】:感谢@menghan 的解决方案和@OutOfFoodException 改进。但请记住,对于 gunicorn=20.0.4
使用 -b, --bind
option 绑定服务器套接字。结果命令对我来说是这样的:
python3 manage.py gunicorn -b 0.0.0.0:5000
from yourapp import app
from flask.ext.script import Manager, Command, Option
class GunicornServer(Command):
"""Run the app within Gunicorn"""
def get_options(self):
from gunicorn.config import make_settings
settings = make_settings()
options = (
Option(*klass.cli, action=klass.action)
for setting, klass in settings.iteritems() if klass.cli
)
return options
def run(self, *args, **kwargs):
from gunicorn.app.wsgiapp import WSGIApplication
app = WSGIApplication()
app.app_uri = 'manage:app'
return app.run()
manager = Manager(app)
manager.add_command("gunicorn", GunicornServer())
【讨论】:
以上是关于如何使用 Flask-Script 和 Gunicorn的主要内容,如果未能解决你的问题,请参考以下文章