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()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With