How to use Flask-Script and Gunicorn

旧街凉风 提交于 2019-11-27 11:23:27
Sean Lynch

As Dhaivat said, you can just use your Flask app directly with Gunicorn.

If you still want to use Flask-Script, you will need to create a custom Command. I don't have any experience with Gunicorn, but I found a similar solution for Flask-Actions and ported it to Flask-Script, although be warned, it's untested.

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

You can then either register it to replace Flask's local development server at python manage.py runserver

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

or register as a new command such as python manage.py gunicorn

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

Edit June 2016: With the latest version of Flask-Script, change the method handle with __call__. old flask-script vs new flask-script

menghan

I wrote a better version of GunicornServer based on Sean Lynch's, the command now accept all gunicorn's arguments

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

Based the answer of the Sean, I also wrote a version more preferred to me.

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

you can run the gunicorn using command like thispython manager.py gunicorn

Dhaivat Pandya

Flask actually has docs to run Gunicorn here.

You have to remember that Gunicorn is a WSGI server with some niceties.

I will elaborate further on the answer by @NinjaDQ. If you want to use app_uri attribute for defining for example the flask application configuration file and custom command line arguments at the same time, you need to use WSGIApplication. The problem is that this application overrides the command line arguments thus it is necessary to ignore the 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()

Based on menghan's answer, receive all arguments from 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()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!