Comment utiliser flasque-Script et Gunicorn

je travaille sur une application Flask en utilisant le serveur Flask intégré dans dev server. Je l'ai commencé en utilisant Flask-Script. Je veux passer à L'utilisation de Gunicorn comme serveur web. Pour ce faire, ai-je besoin d'écrire une sorte de code d'intégration entre Flask-Script et Gunicorn? Ou est-ce que Flask-Script n'est pas pertinent pour lancer L'application avec Gunicorn?

Merci d'avance!

accessoires à @ sean-lynch. Ce qui suit est le code de travail Testé sur la base de sa réponse. Les changements que j'ai faits étaient les suivants:

  • les Options qui ne sont pas reconnues par Gunicorn sont retirées de sys.argvremove_non_gunicorn_command_line_args() avant d'essayer de démarrer le serveur. Sinon Gunicorn lance une erreur avec un message comme celui-ci:error: unrecognized arguments: --port 5010. - Je supprimer -p parce que, même si elle ne cause pas l'erreur, C'est seulement parce que Gunicorn pense que c'est la forme courte de son pidfile option, qui n'est évidemment pas ce qu'on veut.

  • GunicornServer.handle() signature modifiée pour correspond à la méthode qu'il supplante, C'est-à-dire la commande.la poignée()

-

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())
17
demandé sur Julian A. 2013-01-28 20:30:17

6 réponses

comme Dhaivat l'a dit, Vous pouvez utiliser votre flasque directement avec Gunicorn.

si vous voulez toujours utiliser Flask-Script, vous devrez créer un custom Command. Je n'ai pas d'expérience avec Gunicorn, mais j'ai trouvé un similaire solution pour Flacon-Actions et porté à en Flacon de Script, mais attention, c'est non testé.

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

vous pouvez alors soit l'enregistrer pour remplacer le flacon serveur de développement localpython manage.py runserver

manager.add_command("runserver", GunicornServer())

ou vous inscrire comme une nouvelle commande telle que python manage.py gunicorn

manager.add_command("gunicorn", GunicornServer())

Édition Juin 2016: avec la dernière version de Flask-Script, changez la méthode handle__call__. vieux flacon de script et nouveau flacon-script

13
répondu Sean Lynch 2016-07-10 02:44:48

j'ai écrit une meilleure version de GunicornServer basé sur Sean Lynch, la commande accepte maintenant tous les arguments de 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
répondu menghan 2014-09-21 02:11:05

basé sur la réponse du Sean, j'ai aussi écrit une version plus préférée à moi.

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

vous pouvez exécuter le gunicorn en utilisant la commande suivantepython manager.py gunicorn

3
répondu NinjaDQ 2015-06-11 18:52:34

Flask a en fait docs pour exécuter Gunicorn ici.

vous devez vous rappeler que Gunicorn est un serveur WSGI avec quelques subtilités.

2
répondu Dhaivat Pandya 2014-11-18 09:36:55

j'expliquerai plus en détail la réponse de @NinjaDQ. Si vous souhaitez utiliser app_uri attribut pour définir par exemple le fichier de configuration de l'application flask et les arguments personnalisés en ligne de commande en même temps, vous devez utiliser WSGIApplication. Le problème est que cette application overrides les arguments de la ligne de commande il est donc nécessaire d'ignorer le 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
répondu skornos 2017-06-23 06:29:26

basé sur la réponse de menghan, recevez tous les arguments de L'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()
0
répondu OutOfFoodException 2017-07-31 18:07:21