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

Ben*_*ing 54 django nginx upstart reload gunicorn

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

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

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

Rob*_*ing 84

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

kill -HUP <pid>
Run Code Online (Sandbox Code Playgroud)

(详见常见问题)

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

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

你显然可以用pidof,或者类似的东西ps.

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

  • 来自`supervisorctl help pid`:`pid <name>按名称获取单个子进程的PID.(快速测试验证).没有这个名字,它就是`supervisorctl`的PID. (4认同)
  • 实际上,[pidfile setting](http://supervisord.org/configuration.html?highlight=pidfile)仅支持supervisord进程本身.而不是所有sed'ing,为什么不使用`supervisorctl pid gunicorn | xargs ......`?! (3认同)
  • 如果您想使用[pidfile](http://gunicorn.org/configure.html#pidfile),你仍然可以请求gunicorn将其pid写入文件,但要小心将它放在用户设置的主管所在的位置运行gunicorn将有权写! (2认同)
  • @ScottStafford,`supervisorctl reload`要求supervisor守护进程重新加载其配置.也许你的意思是`supervisorctl restart`?这只是开始后停止的简写,所以枪炮大师和所有工人都被摧毁了.使用`SIGHUP`让gunicorn主人跑; 新工人被创造,老人被优雅地杀害.没有请求被删除.更清洁. (2认同)
  • `supervisorctl signal HUP NAME` 也应该可以解决问题。http://supervisord.org/running.html#signals (2认同)

tho*_*ulb 27

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

ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP
Run Code Online (Sandbox Code Playgroud)


Gar*_*ary 18

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

sudo reload jobname
Run Code Online (Sandbox Code Playgroud)

根据initctl(Upstart)联机帮助页,reload将向HUP进程发送信号:

reload JOB [KEY=VALUE]...

       Sends the SIGHUP signal to running process of the named JOB instance.
Run Code Online (Sandbox Code Playgroud)

......对于Gunicorn而言,将会重启(请参阅常见问题解答).

  • noob问题:并且是`jobname`是我从流程本身得到的东西还是我传入gunicorn的选项? (2认同)
  • @TheGrimmScientist,`jobname` 是你的新贵工作/配置的名称。例如,对于 `/etc/init/foo.conf` 中的新贵工作,`foo` 将是工作名称。 (2认同)

np8*_*np8 7

Systemd,gunicorn和Ubuntu

如果您使用systemd运行gunicorn服务,这是单行.

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

细节一步一步

由于gunicorn文档告诉正确重新加载worker的正确方法是使用kill -HUP <Main PID>,<Main PID>主进程的进程id 在哪里,我们使用systemctl提取主PID,然后运行kill -HUP <Main PID>.

1)使用服务名称从systemd获取有关进程的信息

systemctl status gunicorn 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

2)获取主炮声过程的进程ID(PID)

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

  • s用于将所述替代的命令,g意味着搜索整个输入全局.
  • -n标志告诉sed 不要打印每一行(或实际上,不打印任何东西.)
  • p在年底告诉sed 打印匹配行.
  • 我们搜索.*Main PID: \(.*\)$,这是一个正则表达式模式,它有以下部分:.*匹配任何字符(.)零次或多次(*).然后我们搜索Main PID:后跟任何字符,重复零次或多次(.*).为了捕获Main PID:-text 之后的所有字符,我们将.*括号括起来,用反斜杠转义:\(.*\).$表示行结束.
  • sed命令的"替换为此"部分只是\1,这意味着第一个捕获的字符集.

示例输出:

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

3)摆脱多余的角色

管道输出切割.的cut -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
Run Code Online (Sandbox Code Playgroud)

4)使用主PID

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

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

基本上和我一样

echo <Main PID > | xargs kill -HUP
Run Code Online (Sandbox Code Playgroud)

转化为

kill -HUP <Main PID >
Run Code Online (Sandbox Code Playgroud)

编辑

一个更强大的解决方案是使用cut -f1 -d$'\n'grep -m1 ""在前面cut -f1 -d' ',仅选择比赛的第一行.我无法弄清楚任何情况Main PID:,虽然会有两场比赛.


joh*_*all 6

我们在 Supervisor 下运行 Gunicorn,但这是我们发现的最简单、最干净的方法,可以在 Gunicorn 感到困惑时优雅地重新加载它:

sudo pkill -HUP -f gunicorn.*master
Run Code Online (Sandbox Code Playgroud)


Myk*_*ych 6

也许不是问题的直接答案,但对于那些只是在寻找重新启动gunicornWeb 服务器的方法的人,您可以使用killall gunicorn然后执行命令再次启动 gunicorn。例如:

killall gunicorn
gunicorn --bind 0.0.0.0:80 --reload app:app
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然这会起作用,但这可能是不好的做法。优雅地重新加载 Gunicorn 将允许活动连接按其应有的方式完成。仅仅杀死东西就会破坏这些连接,如果有东西保持打开状态并且gunicorn不在那里说关闭它,你可能会遇到一些蹩脚的问题。但是,如果您的站点/项目/约束足够简单,这对我来说当然没问题。 (3认同)