Flask is a very popular framework that is widely used to create APIs in Python. Gunicorn is a WSGI HTTP Server that many use to launch their Python/Flask programs behind a web server. In production use, you are probably launching gunicorn in a daemon-ized mode, with multiple worker threads. Unfortunately, gunicorn does not have an easy way to stop those worker threads later.

Below is a start/stop script in a Makefile format that provides an elegant solution to this challenge:

default: start

module:=helloservice
app:=api

.PHONY: start
start:
	@ ./venv/bin/gunicorn -b "0.0.0.0:8123" \
	-w 4 --daemon ${module}:${app}

.PHONY: show
show:
	ps -ef | grep -i gunicorn

.PHONY: stop
stop:
	@ for pid in \
	$$(ps -eo pid,command | grep "gunicorn.*${module}:${app}" \
	| grep -v grep | awk '{print $$1}'); do \
	kill -9 $${pid}; \
	done 

In case you are wondering, this assumes that your code is in a file called helloservice.py, and in its simplest form may look something like the following:

from flask import Flask
api = Flask(__name__)


@api.route('/')
def hello():
    return "Hello World!"


@api.route('/<name>')
def hello_name(name):
    return "Hello {}!".format(name)

if __name__ == '__main__':
    api.run()

Bonus: Python’s Virtual Environments and Direnv

If you have been writing in Python for a while you probably already know that you want to write each application in its own virtual environment (or a Docker container, but that’s a separate topic). Creating a virtual environment, if you already have Python3 installed is very easy:

python3 -m venv venv

will create a folder “venv” in the current directory that allows you to activate the virtual environment with an easy:

source venv/bin/activate

Once activated, “python” will point to the python3 version from the virtual environment, so will “pip” and anything you install will be confined to that virtual environment.

You can just as easily de-activate the virtual environment by writing

deactivate

while in the active environment.

Pretty sweet, but can we make it even better? What if the environment activated itself when you entered the folder (in terminal) and de-activated when you switch to some other folder? Not bad?

You can do all of that with the direnv utility. To make it happen:

  1. Install “direnv” (e.g. sudo apt-get install direnv)
  2. Hook direnv into your shell with a command appropriate for your shell. E.g. for Bash, put eval "$(direnv hook bash)" in .bashrc
  3. Restart your session so that your shell init script gets activated
  4. Go to the folder where you want automatic environment. Let’s assume you already have the “venv” folder there created (if not - follow the steps earlier in this section i.e. python3 -m venv venv).
  5. Put activation code into the .venvrc file in that folder:
    . venv/bin/activate
    unset PS1
    
  6. Save the file. You will get an error direnv warning about “.envrc is blocked”
  7. Unblock direnv by running direnv allow .
  8. It should all work at this point. If you exit the folder from terminal, and enter again - your virtual env will be enabled and it will be disabled when you switch to somewhere else.

Enjoy!