Run Flask Restplus APIs through Gunicorn - python

I have a sample Flask-RestPlus application as myapp.py:
from flask import Flask
from flask_restplus import Resource, API
API = Api(version='1.0', title='my_routes')
MY_NAMESPACE = API.namespace('v1.0/routes', description='v1.0 routes')
def initialize():
app = Flask(__name__)
API.init_app(app)
API.add_namespace(MY_NAMESPACE)
return app
#MY_NAMESPACE.route('/hello')
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
if __name__ == '__main__':
MY_ROUTE = initialize()
MY_ROUTE.run(host='0.0.0.0', port=8080)
This works fine if I am running python myapp.py. Since I want to run to run this code on production, I want to use Gunicorn. I have gunicorn installed on my UNIX machine. Sample code from https://gunicorn.org/ works perfectly fine. How do I run code in my case? I tried:
gunicorn -w 4 myapp:initialize
gunicorn -w 4 "myapp:initialize()"
gunicorn -w 4 myapp:main
But none of them worked. Do I have to make some changes in code?

In your myapp.py, turn your part:
if __name__ == '__main__':
MY_ROUTE = initialize()
MY_ROUTE.run(host='0.0.0.0', port=8080)
into:
app = initialize() # app has to be accessible outside if
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
and then run
gunicorn --bind 0.0.0.0:8080 --workers 4 myapp:app --log-level debug
if you want to run in production mode, specify --log-level info.

Related

Python flask app with Nginx and uWSGI gives Internal Server Error when writing it as class

I am building a API that uses flask. I am going to use uWSGI and NGINX in production. The API is working as it is, but I am trying to rebuild it to use classes. When I run it after I have build it as a class it gives me Internal Server Error.
The following files are working:
src/server.py
from flask import Flask
app = Flask(__name__)
#app.route("/ping")
def ping():
return "pong"
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
src/wsgi.py
from src.server import app
if __name__ == "__main__":
app.run()
When I try to build it as class then I get Internal Server Error
src/server.py
from flask import Flask
class Main:
app = Flask(__name__)
def __init__(self):
#self.app.route("/ping")
def ping():
return "pong"
if __name__ == "__main__":
main = Main()
main.app.run(host="0.0.0.0", debug=True)
src/wsgi.py
from src.server import Main
if __name__ == "__main__":
main = Main()
main.app.run()

Initialize Flask-SocketIO python app on heroku

I'm new to python, so this might be a dumb question, but I have the following issue:
I'm trying to deploy a Flask-SocketIO app to heroku, my app.py looks like this:
app = Flask(__name__)
socketio = SocketIO(app)
opt: Dict[Any, Any] = {}
.
.
#socketio.on('connect')
def joined():
test = json.dumps(opt)
emit('test', test)
.
.
if __name__ == '__main__':
opt = setup_args()
socketio.run(app)
My procfile looks like this:
web: gunicorn -k flask_sockets.worker app:app
If i run heroku local my server starts as expected, and I can establish a socket conection with my client, but my variable opt seems not to be filled. From what i've read in the docs, this is because the procfile does the socketio.run(app) for me, and my __main__ part is not getting executed.
I need to somehow trigger a method that initializes some variables in my app.py.
How can I achieve this?
Thanks
Is there a reason why you don't simply move opt = setup_args() out of the if statment, and move it, say, somewhere at the top of the file?

Gunicorn does not execute statements within main

from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route('/api', methods=['POST'])
def predict():
pass
#Some statements to predict something
if __name__ == '__main__':
print("Hello World")
app.run(host='0.0.0.0', debug=True)
When I run as
gunicorn -b 0.0.0.0 app:app I do not see the print statement. However when I run as python app.py, the "Hello World" gets printed. The app runs but it does not execute the print statement. Any idea what causes the Gunicorn to ignore what is within main()?
When you run as gunicorn -b 0.0.0.0 app:app, gunicorn will only import the app from your app.py file. It will skip statements from the if __name__ == '__main__' block and hence you're not seeing the output from the print statement.
But when you run as python app.py, if __name__ == '__main__' block will be the entry point and hence print statement gets executed.
Also note that, the app.run(host='0.0.0.0', debug=True) line in if __name__ == '__main__' will start the development server and not the gunicorn server.
Attaching the link here for the similar question:
code before app.run() can not be run in gunicorn+flask

Running supervisor on an Amazon EC2 linux instance

I am running a python flask app on an amazon ec2 linux instace.
MY python app looks like:
application.py
#!flask/bin/python
from flask import Flask
application = Flask(__name__)
#application.route('/', methods=['GET', 'POST'])
def index():
return '{"Output":"Hello World"}'
if __name__ == '__main__':
application.run(host='0.0.0.0', port=80, debug=False)
my supervisor config looks like:
supervisor.conf
[program:flaskapplication]
command = /home/ec2-user/myapp/venv/bin/python /home/ec2-user/myapp/application.py
stdout_logfile = /var/log/watcher-stdout.log
stdout_logfile_maxbytes = 10MB
stdout_logfile_backups = 5
stderr_logfile = /var/log/watcher-stderr.log
stderr_logfile_maxbytes = 10MB
stderr_logfile_backups = 5
When I do the following command:
supervisorctl -c supervisor.conf
I get the following response:
00:00:00 /home/ec2-user/myapp/venv/bin/python2.7 /home/ec2-user/myapp/venv/bin/supervisord -c supervisor.conf
But when I hit the Amazon instance link, nothing is displayed. I get a server not responding page. What am I doing wrong?
I think you probably need an end-point:
>>> #application.route('/say_hi', methods=['POST'])
I realized that port 80 by default is not configured to be an incoming port in the EC2 security group. Once I added port 80 to be a verified incoming group, I was able to run the application.

I don't need the run() method in a Flask application?

I have a Flask application setup on my linode with a directory structure like so:
|--------flask-test
|----------------app
|-----------------------static
|-----------------------templates
|-----------------------venv
|-----------------------__init__.py
|-----------------------main.py
my __init__.py is:
# __init__.py
from flask import Flask
from main import main
app = Flask(__name__)
app.register_blueprint(main)
app.run()
and main.py like so:
# main.py
from flask import Blueprint
main = Blueprint('main',__name__)
#main.route("/")
def hello():
return "Hello World!"
#main.route("/england/")
def england():
return "Hello England!"
If I run the app locally there are no issues. If I go to my server address in the web browser I get an internal server error. However if I remove the line: app.run from __init__.py it works fine. Why is this? Why do I not need the run method?
You should do
if __name__ == '__main__':
app.run()
The reason is that Apache or NGINX or some other web server loads your app directly on the server but app.run() runs flask's internal web-server so you can test your app.
It is a bit odd to have app.run() inside of the __init__.py file, normally it would be in a separate application script you run, where it would be written as:
if __name__ == '__main__':
app.run()
This way app.run() is only called when that script is executed as the application.
This is necessary because you do not want app.run() called when hosting under a WSGI server such as mod_wsgi or gunicorn. When using such WSGI servers, even if reusing the same script file as holder of the WSGI application entrypoint, __name__ wouldn't be set to __main__ but the basename of the script file. This ensures that app.run() isn't called where it is the separate WSGI server which is running the web server component.

Categories

Resources