How to stop gunicorn properly

I'm starting gunicorn with the Django command python manage.py run_gunicorn. How can I stop gunicorn properly?

Note: I have a semi-automated server deployment with fabric. Thus using something like ps aux | grep gunicorn to kill the process manually by pid is not an option.

129593 次浏览

One option would be to use Supervisor to manage Gunicorn.

Then again i don't see why you can't kill the process via Fabric. Assuming you let Gunicorn write a pid file you could easily read that file in a Fabric command.

Something like this should work:

run("kill `cat /path/to/your/file/gunicorn.pid`")

To see the processes is ps ax|grep gunicorn and to stop gunicorn_django is pkill gunicorn.

kill -9 `ps -eo pid,command | grep 'gunicorn.*${moduleName:appName}' | grep -v grep | sort | head -1 | awk '{print $1}'`

ps -eo pid,command will only fetch process id, command and args out

grep -v grep to get rid of output like 'grep --color=auto xxx'

sort | head -1 to do ascending sort and get first line

awk '{print $1}' to get pid back

One more thing you may need to pay attention to: Where gunicorn is installed and which one you're using?

Ubuntu 16 has gunicorn installed by default, the executable is gunicorn3 and located on /usr/bin/gunicorn3, and if you installed it by pip, it's located on /usr/local/bin/gunicorn. You would need to use which gunicorn and gunicorn -v to find out.

pkill gunicorn stops all gunicorn daemons. So if you are running multiple instances of gunicorn with different ports, try this shell script.

#!/bin/bash
Port=5000
pid=`ps ax | grep gunicorn | grep $Port | awk '{split($0,a," "); print a[1]}' | head -n 1`
if [ -z "$pid" ]; then
echo "no gunicorn deamon on port $Port"
else
kill $pid
echo "killed gunicorn deamon on port $Port"
fi

ps ax | grep gunicorn | grep $Port shows the daemons with specific port.

To start the service which is running on gunicorn

sudo systemctl enable myproject


sudo systemctl start myproject

or

sudo systemctl restart myproject

But to stop the service running on gunicorn

sudo systemctl stop myproject

to know more about python application hosting using gunicorn please refer here

pkill gunicorn

or

pkill -P1 gunicorn

should kill all running gunicorn processes

Start:

gunicorn --pid PID_FILE APP:app

Stop:

kill $(cat PID_FILE)

The --pid flag of gunicorn requires a single parameter: a file where the process id will be stored. This file is also automatically deleted when the service is stopped.

I have used PID_FILE for simplicity but you should use something like /tmp/MY_APP_PID as file name.

If the PID file exists it means the service is running. If it is not there, the service is not running. To stop the service just kill it as mentioned.

You could also want to include the --daemon flag in order to detach the process from the current shell.

Here is the command which worked for me :

pkill -f gunicorn

It will kill any process with the name gunicorn

The above solutions does not remove pid file when the process is killed.

cat <pid-file> | xargs kill -2

This solution reads pid file and send interrupt signal. This closes gunicorn properly and pid file is also removed.

PID file can be generated by

gunicorn --pid PID-FILE

or by adding the following in config file

pidfile = "pid_file"

In your terminal, do:

ps ax|grep gunicorn

Then to kill the Gunicorn process, just do that:

kill -9 <gunicorn pid number>

In my case I dealt with many processes

For example: kill -9 398 399 4225 4772

If we run:

pkill gunicorn

We stop all gunicorn services, in this case to start gunicorn we only need to stop the parent process associated with the service that attends the port where gunicorn will be executed.

The following script searches for said process (pid), if it exists it kills this process:

#!/bin/bash
# ---------------------
stop_unicorn_on_port() {
pid=$(lsof -w -t -i "TCP:${1}" | head -1)
if [ -z "${pid}" ]; then
echo "🦄 no service deamon on port ${1}"
else
kill -9 "${pid}"
echo "🦄 killed service deamon(${pid}) on port ${1}"
fi
}
# Example/Testing
stop_unicorn_on_port 5000
stop_unicorn_on_port 5001
stop_unicorn_on_port 5002

more info check: man lsoft

  • -t specifies that lsof should produce terse output with process identifiers only and no header - e.g., so that the output may be piped to kill(1). -t selects the -w option.

  • -iselects the listing of files any of whose Internet address matches the address specified in i. If no address is specified, this option selects the listing of all Internet and x.25 (HP-UX) network files...

Here are some sample addresses:


-i6 - IPv6 only
TCP:25 - TCP and port 25
@1.2.3.4 - Internet IPv4 host address 1.2.3.4

I built upon @David's recommendation to use --pid (PID_FILE) to fix the problem I faced because killing the parent pid didn't kill worker processes.

import os
import sys


import psutil




def stop_pid(pid):
if sys.platform == 'win32':
p = psutil.Process(pid)
p.terminate()  # or p.kill()
else:
os.system('kill -9 {0}'.format(pid))




def get_child_pids(ppid):
pid_list = []
for process in psutil.process_iter():
_ppid = process.ppid()
if _ppid == ppid:
_pid = process.pid
pid_list.append(_pid)
return pid_list




def send_kill_cmd(ppid, cpids):
stop_pid(ppid)  # Killing the parent proc first
for pid in cpids:
stop_pid(pid)




if __name__ == '__main__':
parent_pid = int(sys.argv[1])
child_pids = get_child_pids(parent_pid)
send_kill_cmd(parent_pid, child_pids)

Then finally excecuted above python script with below commands

#!/bin/bash


FILE_NAME=PID_FILE
if [ -f "$FILE_NAME" ]; then
pypy stop_gunicorn.py "$(cat PID_FILE)"
echo "killed -  $(cat PID_FILE) and it's child processes."
sleep 2
fi


echo 'Starting gunicorn'
nohup gunicorn --workers 1 --bind 0.0.0.0:5050 app:app --thread 50 --worker-class eventlet --reload --pid PID_FILE > nohup_outs/nohup_process.out &