Search code examples
pythonflaskuwsgi

Run flask application with uWSGI


I have a flask application and I would like to run it in a "production" way using uwsgi.

I have my launcher.py:

from app import app
import db

if __name__ == "__main__":
    db.init()
    app.run()

If I run the application with simply python launcher.py it's all ok. Especially, the db.init() is called correctly.

However, if I run using uwgsi with uwsgi app.ini , db.init() is not called.

Here is app.ini:

[uwsgi]
wsgi-file = launcher.py
callable = app
socket = :8080

I'm new with flask and uwsgi so probably I missed something but I could not find the solution in the different tutorials I read.

Also, in case you need it to understand the project, here is app.py:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "hello from flask"

if __name__ == "__main__":
    db.init()
    app.run()

All files are in the same level in my project:

webserver/
    - app.ini
    - launcher.py
    - app.py
    - db.py

So, what am I doing wrong here?


Solution

  • Your code under if __name__ == "__main__": is not executed because uwsgi does not run your script like python app.py. Instead it imports the module specified in wsgi-file and looks for an object specified as callable (app in our case). You can test it by using the following script:

    from flask import Flask
    
    app = Flask(__name__)
    
    print(__name__)
    if __name__ == '__main__':
        app.run()
    

    If you run it with python ./flask_app.py then the output will be

    $ python ./flask_app.py
    __main__
     * Serving Flask app 'app' (lazy loading)
     * Environment: production
       WARNING: This is a development server. Do not use it in a production deployment.
       Use a production WSGI server instead.
     * Debug mode: off
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    

    (notice __main__ - it means we're running the script). However if you run it with uwsgi the __name__ will be app (it will be the name of your file, so app in my case):

    $ uwsgi --http 127.0.0.1:5000 --module app:app 
    ...
    *** Operational MODE: single process ***
    app
    WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7fb2d0c067b0 pid: 46794 (default app)
    *** uWSGI is running in multiple interpreter mode ***
    spawned uWSGI worker 1 (and the only) (pid: 46794, cores: 1)
    

    Similar output will be if you run your app with FLASK_APP=app flask run - it does not execute script, it just imports it and uses app object from it.

    So, in order to initialize database you should either move your db initialization out of if __name__ == "__main__":

    from flask import Flask
    
    app = Flask(__name__)
    
    
    class DB:
        def init(self):
            self.data = 'Hello, World'
    
    
    db = DB()
    
    
    @app.route("/")
    def hello_world():
        return db.data
    
    
    db.init()
    
    if __name__ == '__main__':
        app.run()
    

    Or add a before_first_request handler:

    # replace db.init() with 
    @app.before_first_request
    def init_db():
        db.init()
    

    Notice the difference between them - if you put db.init() as a top-level statement it will be executed once you load app.py. If you register a before_first_request callback it will be executed once first request arrives to your application. Pick the one that works best for you.