私はFlaskの組み込み開発サーバーを使用してFlaskアプリに取り組んでいます。Flask-Scriptを使用して起動します。WebサーバーとしてGunicornを使用するように切り替えたいと思います。 Flask-ScriptとGunicornの間に何らかの統合コードを書く必要がありますか?それともFlask-ScriptはGunicornを使用してアプリを実行することとは無関係ですか?
前もって感謝します!
@ sean-lynchへの小道具。以下は、彼の答えに基づいて動作し、テストされたコードです。私が行った変更は次のとおりです。
Gunicornによって認識されないオプションは、サーバーを起動しようとする前に、remove_non_gunicorn_command_line_args()
のsys.argv
から削除されます。それ以外の場合、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())
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の ローカル開発サーバー at python manage.py runserver
を置き換えることができます。
manager.add_command("runserver", GunicornServer())
または、python manage.py gunicorn
などの新しいコマンドとして登録します
manager.add_command("gunicorn", GunicornServer())
2016年6月の編集:最新バージョンのFlask-Scriptで、メソッドhandle
を__call__
に変更します。 古いフラスコスクリプト vs 新しいフラスコスクリプト
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())
ショーンの答えに基づいて、私は自分にもっと好まれるバージョンも書きました。
@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()
thispython manager.py gunicorn
のようなコマンドを使用してgunicornを実行できます
Flaskには、実際にはGunicornを実行するためのドキュメントがあります ここ 。
Gunicornはいくつかの優れた機能を備えたWSGIサーバーであることを覚えておく必要があります。
Menghanの回答に基づいて、アプリケーション構成からすべての引数を受け取ります。
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()
@NinjaDQによる回答についてさらに詳しく説明します。たとえば、flaskアプリケーション構成ファイルとカスタムコマンドライン引数を同時に定義するためにapp_uri
属性を使用する場合は、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()