Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Flask app running with gunicorn

I am new to Flask/Python and the question might be silly or I might be missing something obvious, so please bear with me.

I have created a Flask app and the structure is as follow:

myproject
  api
    __init__.py
    api.py
    application.py
    config.py
    models.py
  migrations
    ...
  appserver.py
  manage.py
  Procfile
  requirements.txt

The contents of my appserver.py:

from api.application import create_app

if __name__ == '__main__':
  create_app = create_app()
  create_app.run()

The contents of my api/application.py:

from flask import Flask


def create_app(app_name='MYAPPNAME'):
  app = Flask(app_name)
  app.config.from_object('api.config.DevelopmentConfig')

  from api.api import api
  app.register_blueprint(api, url_prefix='/api')

  from api.models import db
  db.init_app(app)

  return app

When I run my server locally with python appserver.py everything works as expected. When I try to run gunicorn like so: gunicorn --bind 127.0.0.1:5000 appserver:create_app I get this error: TypeError: create_app() takes from 0 to 1 positional arguments but 2 were given

What am I doing wrong here?

like image 467
WagnerMatosUK Avatar asked Jul 18 '18 07:07

WagnerMatosUK


1 Answers

I would suggest you update the code inside the appserver.py files as shown below:

from api.application import create_app

if __name__ == '__main__':
    create_app = create_app()
    create_app.run()
else:
    gunicorn_app = create_app()

and then run the app as follows

gunicorn --bind 127.0.0.1:5000 appserver:gunicorn_app

The reason for the above steps is as follows:

Running the server locally

When you run the server locally with python appserver.py the if block gets executed. Hence the Flask object gets created via your create_app method and you are able to access the server.

Running the server via Gunicorn

When you run the server via Gunicorn, you need to specify the module name and the variable name of the app for Gunicorn to access it. Note that the variable should be a WSGI callable object for e.g a flask app object. This is as per the definition in Gunicorn Docs.

When you were running the Gunicorn command gunicorn --bind 127.0.0.1:5000 appserver:create_app, it mistook create_app as the WSGI callable object(Flask app object). This threw the error as create_app is just a regular method which returns the Flask app object on correct invocation.

So we added the part of creating the object in the else block gunicorn_app = create_app() and called this via the Gunicorn using gunicorn --bind 127.0.0.1:5000 appserver:gunicorn_app

The other thing that you need to note is when you run python appserver.py the if block gets triggered since it is the main file getting executed. Where as when you gunicorn --bind 127.0.0.1:5000 appserver:create_app the appserver.py gets imported by gunicorn. Hence the else block gets triggered. This is the reason we have placed gunicorn_app = create_app() in the else block.

I hope the above explanation was satisfactory. Let me know if you have not understood any part.

like image 78
Pranav Kundaikar Avatar answered Sep 16 '22 11:09

Pranav Kundaikar