69

我正在寻找比sudo restart projectname每次发出更好的东西 a git pull origin master,它会拉下我对 Django 项目的最新更改。我相信这个restart命令与 Upstart 相关,我用它来启动/启动我的 Gunicorn 服务器进程。

此重新启动会导致短暂的中断。访问 Web 服务器 (nginx) 的用户将获得 500,因为 Gunicorn 仍在重新启动。实际上,它似乎立即重新启动,但页面加载需要几秒钟。

关于如何使这个无缝的任何想法?理想情况下,我想git pull自动发布我的和 Gunicorn 重新加载。

4

9 回答 9

103

你可以告诉 Gunicorn 使用HUP信号优雅地重新加载,如下所示:

kill -HUP <pid>

(详情请参阅常见问题解答

我使用Supervisor来控制我的 Gunicorn 服务器,这允许我在部署后使用这种(有点 hacky)方式重新加载 Gunicorn:

supervisorctl status gunicorn | sed "s/.*[pid ]\([0-9]\+\)\,.*/\1/" | xargs kill -HUP

您显然可以使用pidof, 或实现类似的效果ps

这实际上是从Fabric脚本运行的,所以我什至根本不需要登录到服务器。

于 2012-03-27T08:12:39.477 回答
33

对于那些不使用 supervisord 的人:Rob 所说的,它也适用于 ps,

ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP
于 2015-01-11T18:20:44.913 回答
21

为了优雅地重新加载,您应该改用 Upstart 的reload命令,例如:

sudo reload jobname

根据 initctl (Upstart) 手册reload将向进程发送HUP信号:

reload JOB [KEY=VALUE]...

       Sends the SIGHUP signal to running process of the named JOB instance.

...这对于 Gunicorn 将触发正常重启(请参阅常见问题解答)。

于 2013-04-26T14:32:27.137 回答
14

Systemd, gunicorn & Ubuntu

Here is the one-liner, if you are running your gunicorn service with systemd.

systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

Details step by step

Since the gunicorn docs tell that the correct way to gracefully reload the workers is by using kill -HUP <Main PID>, where <Main PID> is the process id of the master process, we extract the master PID using systemctl, and run kill -HUP <Main PID>.

1) Get info about the process from systemd using the name of the service

systemctl status gunicorn 

where gunicorn is the name of the service, located at /etc/systemd/system/.

Example output:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn
● gunicorn.service - Gunicorn server for yourproject.com
   Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2017-11-04 19:16:24 UTC; 1h 15min ago
 Main PID: 10673 (gunicorn)
   CGroup: /system.slice/gunicorn.service
           ├─10673 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
           ├─11069 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
           ├─11070 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
           └─11071 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application

Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11047] [INFO] Booting worker with pid: 11047
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11048] [INFO] Booting worker with pid: 11048
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Handling signal: hup
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Hang up: Master
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11046] [INFO] Worker exiting (pid: 11046)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11047] [INFO] Worker exiting (pid: 11047)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11048] [INFO] Worker exiting (pid: 11048)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11069] [INFO] Booting worker with pid: 11069
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11070] [INFO] Booting worker with pid: 11070
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11071] [INFO] Booting worker with pid: 11071

2) Get the process ID (PID) of the main gunicorn process

The sed command works like follows: sed 's/<search this>/<replace with this>/g'

  • s means for the substitute command, and g means that search the whole input globally.
  • The -n flag tells sed not to print every line (or actually, not to print anything.)
  • The p at the end tells sed to print the matched line.
  • We search for .*Main PID: \(.*\)$, which is a regular expression pattern, which has following parts: .* matches any character (.) zero or more times (*). Then we search for Main PID: followed by any characters, repeated zero or more times (.*). To capture all characters after the Main PID:-text, we enclose the .* into parenthesis, which are escaped with backslashes: \(.*\). $ indicates line end.
  • The "replace with this" part of the sed command is just \1, which means the first captured set of characters.

Example output:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p'
10673 (gunicorn)

3) Get rid of the extra characters

Pipe the output to cut. The cut -f1 -d' ' means, that

  • The string is space delimited: Here -d determines the delimiter, which is the characted just after the -d. Since the delimiter is space, we enclose that in quotes.
  • -f means just that cutting is made using the delimiter (and not by bytes), and -f1 means that we want to take out the first element of the list.

Example output:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' '
10673

4) Use the Main PID

Piping to xargs means just running the command with arguments from the pipe on the left hand side. Since we are piping just the Main PID to xargs,

 systemctl status gunicorn-django |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

is basically just the same thing as

echo <Main PID > | xargs kill -HUP

which translates into

kill -HUP <Main PID >

Edit

A little more robust solution would be to use cut -f1 -d$'\n' or grep -m1 "" in front of cut -f1 -d' ', to pick just the first line of the match. I can't figure out any circumstances, where there would be two matches for the Main PID:, though.

于 2017-11-04T21:12:43.563 回答
6

We run Gunicorn under Supervisor, but this is the simplest, cleanest way we've found to gracefully reload Gunicorn when it gets confused:

sudo pkill -HUP -f gunicorn.*master
于 2015-10-28T22:55:44.087 回答
6

Maybe not a direct answer to the question, but for those who are just looking for a way to restart gunicorn web server, you can use killall gunicorn and then execute a command to start gunicorn again. For example:

killall gunicorn
gunicorn --bind 0.0.0.0:80 --reload app:app

Note: killall gunicorn will terminate all gunicorn processes immediately so make sure you understand what you are doing.

于 2018-10-24T14:29:22.763 回答
2
sudo systemctl restart gunicorn
于 2020-07-18T11:19:30.137 回答
1

If you are running gunicorn on a port rather than a socket, you can find the process id (pid) of gunicorn using fuser command. Then force gunicorn to reload the code by sending a HUP signal.

The command fuser 8000/tcp will list the process ids of all processes using tcp port 8000.

fuser -k 8000/tcp will kill those processes gracelessly which is not recommended.

  • fuser -k -HUP 8000/tcp will force gunicorn using tcp port 8000 to reload the code by sending HUP signal.
于 2020-09-15T06:32:43.447 回答
0

Restart gunicorn service using cmd
systemctl restart gunicorn

else restart gunicorn service and create the sock file again.

于 2019-11-28T07:12:31.657 回答