Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run gunicorn inside python not as a command line?

I have a flask application.

I run it in production with this command:

python -m gunicorn -w 1 -b 0.0.0.0:5000 "path.to.wsgi:return_app()"

Instead, I want to run it inside a my_file.py

I need a function to run and it should accept the app object and port binding and number of workers

How can I do that?

I need something like this psudo code:

import gunicorn

app = return_app()

gunicorn(workers=1, ip="0.0.0.0", port=5000, app=app)

the most important part to me is the app=app part

the main point is that I want to use the app object as an instance of Flask(). I want to directly give app object to gunicorn not throough addressing it in a string

What I have tried: I have opened gunicorn library main.py file

from gunicorn.app.wsgiapp import run
run()

to see how it works but could not figure it out

def run():
    """\
    The ``gunicorn`` command line runner for launching Gunicorn with
    generic WSGI applications.
    """
    from gunicorn.app.wsgiapp import WSGIApplication
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
like image 881
Amin Ba Avatar asked Dec 04 '25 08:12

Amin Ba


1 Answers

My goals weren't exactly the same: I was fine with specifying the app as a string (same as you do with gunicorn on the command line) rather than passing a python app object. Actually I'm not sure if passing a single app object really makes sense, because shouldn't gunicorn have a different app object in each worker that it spawns?

My main concern was that I run gunicorn without the help of subprocess or similar. I also used FastAPI rather than Flask, and (per the current recommended prod FastAPI setup) told gunicorn to spawn uvicorn workers.

This is what I ended up going with (in myproject/web.py):

import multiprocessing

from gunicorn.app.wsgiapp import WSGIApplication


class StandaloneApplication(WSGIApplication):
    def __init__(self, app_uri, options=None):
        self.options = options or {}
        self.app_uri = app_uri
        super().__init__()

    def load_config(self):
        config = {
            key: value
            for key, value in self.options.items()
            if key in self.cfg.settings and value is not None
        }
        for key, value in config.items():
            self.cfg.set(key.lower(), value)


def run():
    options = {
        "bind": "0.0.0.0:8000",
        "workers": (multiprocessing.cpu_count() * 2) + 1,
        "worker_class": "uvicorn.workers.UvicornWorker",
    }
    StandaloneApplication("myproject.main:app", options).run()

My StandaloneApplication is very similar to (and is based on) the one in Zaero Divide's answer in this thread. However, I pass app_uri, and I inherit from WsgiApplication instead of from BaseApplication, which results in gunicorn starting up in basically the same way as when it's invoked from the command line.

Note: in myproject/main.py, I have app = FastAPI(). And in pyproject.toml, under [tool.poetry.scripts], I have web = "myproject.web:run" - so I can start gunicorn with poetry run web. I'm also building an artifact with shiv -c web myproject.whl -o web.pyz, so I can then just run /path/to/web.pyz to start gunicorn.

like image 197
Jaza Avatar answered Dec 07 '25 03:12

Jaza



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!