在'git pull'ing我的Django项目之后,重新启动/重新加载Gunicorn(通过Upstart)的更好方法

时间:2012-03-27 00:34:55

标签: django nginx reload gunicorn upstart

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

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

有关如何实现这一目标的任何想法?理想情况下,我想自动发出git pull和Gunicorn重新加载。

9 个答案:

答案 0 :(得分:80)

你可以告诉Gunicorn使用HUP信号正常重新加载:

kill -HUP <pid>

(有关详细信息,请参阅FAQ

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

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

您显然可以通过pidofps实现类似的功能。

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

答案 1 :(得分:24)

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

ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP

答案 2 :(得分:16)

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

sudo reload jobname

根据initctl(Upstart)manpagereload会向流程发送HUP信号:

reload JOB [KEY=VALUE]...

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

......对于Gunicorn来说,这会引发一场优雅的重启(见FAQ)。

答案 3 :(得分:7)

Systemd,gunicorn&amp; Ubuntu的

如果你使用 systemd 运行你的gunicorn服务,这是单线程。

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

逐步详述

由于gunicorn docs告诉正确重新加载worker的正确方法是使用kill -HUP <Main PID>,其中<Main PID>是主进程的进程ID,我们使用提取主PID systemctl,然后运行kill -HUP <Main PID>

1)使用服务名称

从systemd获取有关进程的信息
systemctl status gunicorn 

其中gunicorn是服务的名称,位于/etc/systemd/system/

示例输出:

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)获取主炮声过程的进程ID(PID)

sed 命令的工作原理如下:sed 's/<search this>/<replace with this>/g'

  • s表示替换命令,而g表示全局搜索
  • -n标志告诉sed 打印每一行(或实际上,不打印任何内容。)
  • 最后的p告诉sed 打印匹配的行
  • 我们搜索.*Main PID: \(.*\)$,这是一个正则表达式模式,其中包含以下部分:.*匹配任何字符(.)零次或多次(*) 。然后我们搜索Main PID:后跟任何字符,重复零次或多次(.*)。要在Main PID: - 文本之后捕获所有字符,我们将.*括在括号中,这些括号使用反斜杠进行转义:\(.*\)$表示行结束。
  • sed命令的“替换为此”部分只是\1,这意味着第一个捕获的字符集。

示例输出:

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

3)摆脱额外的字符

将输出传递给cutcut -f1 -d' '表示

  • 字符串以空格分隔:此处-d确定分隔符,即-d之后的分隔符。由于分隔符是空格,我们用引号括起来。
  • -f表示只使用分隔符(而不是字节)进行剪切,而-f1表示我们想要取出列表的第一个元素。

示例输出:

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

4)使用主PID

管道到xargs意味着只使用左侧管道的参数运行命令。因为我们只将主PID连接到xargs,

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

基本相同
echo <Main PID > | xargs kill -HUP

转换为

kill -HUP <Main PID >

修改

更强大的解决方案是在cut -f1 -d$'\n'前面使用grep -m1 ""cut -f1 -d' '来挑选匹配的第一行。我无法弄清楚任何情况,但Main PID:会有两个匹配。

答案 4 :(得分:2)

我们在Supervisor下运行Gunicorn,但这是我们发现的最简单,最干净的方式,当它被混淆时优雅地重新加载Gunicorn:

sudo pkill -HUP -f gunicorn.*master

答案 5 :(得分:2)

也许不是该问题的直接答案,但是对于那些只想重启gunicorn Web服务器的人,您可以使用killall gunicorn然后执行命令以重新启动gunicorn。例如:

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

注意: killall gunicorn将立即终止所有gunicorn流程,因此请确保您了解自己在做什么。

答案 6 :(得分:2)

sudo systemctl restart gunicorn

答案 7 :(得分:0)

使用cmd重新启动gunicorn服务
systemctl restart gunicorn

否则,重新启动gunicorn服务并再次创建袜子文件。

答案 8 :(得分:0)

如果您在端口而不是套接字上运行 gunicorn ,则可以 使用fuser命令找到gunicorn的进程ID(pid)。然后通过发送HUP信号强制使用枪械来重新加载代码

命令fuser 8000/tcp将列出使用tcp端口8000的所有进程的进程ID。

fuser -k 8000/tcp将毫不客气地杀死那些进程,这是不推荐的。

  • fuser -k -HUP 8000/tcp将使用tcp端口9000强制使用 通过发送HUP信号重新加载代码。