In this tutorial, I will teach you how to deploy Falsk app in prodcution environment. Falsk is a Web framework that can be used to build a website or interface.

When run Flask app directly, we always see the following warning.

1
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.

This message warns us not to use Falsk in production enviroment, as most services needs to process requests parallelly while running Falsk directly can’t support parallel processing. To address this issue, we need to use wsgi server.

In this blog, I will show you using gunicorn to build wsgi server and provide generic code example for you.

Set up environment

First, download the required python libraries.

1
2
pip install gunicorn
pip install gevent

Then, run the following code to check if it is avaliable.

1
2
gunicorn -v
# output: gunicorn (version 21.2.0)

Deploy Flask service using gunicorn

Now, you can write your flask code for processing users’ requests.

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/test', methods=['POST'])
def test():
try:
return jsonify({'status': 'success', 'message': 'ok'})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)})

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8124)

I recommend using configuration file to provide neccessary parameters for gunicorn. So, let’s create a configuration file named gunicorn_conf.py. In this file, you can specify the corresponding settings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# This is a gunicorn config file, which is used to start the server.

preload_app = False # Setting preload_app to False will disable this behaviour, and will result in each worker loading the application code when it starts.
workers = 3 # The number of worker processes for handling requests.
bind = '0.0.0.0:8123' # The socket to bind.
worker_class = 'gevent' # The type of workers to use.
# threads = 6 # The number of worker threads for handling requests.
backlog = 3 # The maximum number of pending connections.
worker_connections = 10 # The maximum number of simultaneous clients.
accesslog = 'logs/access.log' # The Access log file to write to.
access_log_format = '%(h)s %(t)s %(U)s %(q)s' # The access log format.
debug = True # Debug mode.
proc_name = 'gunicorn.pid' # A base to use with setproctitle for process naming.
pidfile = 'logs/gunicorn.pid' # A filename to use for the PID file.
timeout = 300 # Workers silent for more than this many seconds are killed and restarted.

Of course, you should change these settings correspondingly.

Now, you can create another shell file to help you start the gunicorn server. Here I will provide you a example named process.sh.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
# activate python environment
export PATH=/data/XXX/anaconda3/envs/python37/bin:$PATH
source ~/.bashrc

# This is a shell script for starting or stopping python program
# receive one parameter, start or stop

if [ $# -lt 1 ] # if the number of parameters is less than 1
then
echo $0" <start|stop|restart>" # print the usage
exit # exit
else
command=$1 # otherwise, get the first parameter
fi

basepath=$(cd `dirname $0`; pwd) # obtain the absolute path of this shell script
PID=$basepath"/logs/gunicorn.pid" # this is the PID file path of gunicorn

if [ $command == "start" ]; then # if the first parameter is start
if [ -e $PID ]; then # if PID file already exists
echo "ERROR: process aready start, if you want to restart, please first stop process" # print error message
else # else
gunicorn -c gunicorn_conf.py clustered_topic_interface:app > logs/runlog.txt 2>&1 & # luanched gunicorn ***
echo "start success" # print success message
fi
elif [ $command == "stop" ]; then # if the first parameter is stop
if [ ! -e $PID ]; then # if PID file does not exist
echo "please start before stop" # print error message
else # else
kill -9 $(cat ${PID}) # kill the process
echo "stop $(cat ${PID}) success" # print success message
rm $PID # remove the PID file
fi
fi

Now, run the process.sh file to start the flask services. That’s all!