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?
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.