0

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?

iAmoric
  • 1,787
  • 3
  • 31
  • 64
  • Not sure. This post is about running code after `app.run()`. In my case it's before so it should work normally. I just don't see why it's not called – iAmoric Jan 28 '22 at 11:32
  • `__name__ == "__main__"` is only `True` when script is executed like `python app.py`. `uwsgi` just imports the module and uses `app` from it, so your `if __name__ == "__main__"` won't be called – awesoon Jan 28 '22 at 11:35
  • If I remove the if I have the following (the one I'm trying to avoid): ` WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead` – iAmoric Jan 28 '22 at 11:44

1 Answers1

2

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.

awesoon
  • 32,469
  • 11
  • 74
  • 99