web-dev-qa-db-ja.com

Flaskの使用方法-スクリプトとGunicorn

私は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())
18
Julian A.

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 新しいフラスコスクリプト

14
Sean Lynch

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())
8
menghan

ショーンの答えに基づいて、私は自分にもっと好まれるバージョンも書きました。

@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を実行できます

3
NinjaDQ

Flaskには、実際にはGunicornを実行するためのドキュメントがあります ここ

Gunicornはいくつかの優れた機能を備えたWSGIサーバーであることを覚えておく必要があります。

2
Dhaivat Pandya

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()
0

@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()
0
skornos