主管在重启时有一半的时间失败

22

我正在尝试在一台运行Debian 8.1的机器上使用Uwsgi和supervisor部署Django应用程序。

当我通过sudo systemctl restart supervisor重启时,它有一半的概率无法重新启动。

$ root@host:/# systemctl start supervisor
    Job for supervisor.service failed. See 'systemctl status supervisor.service' and 'journalctl -xn' for details.
$ root@host:/# systemctl status supervisor.service
    ● supervisor.service - LSB: Start/stop supervisor
       Loaded: loaded (/etc/init.d/supervisor)
       Active: failed (Result: exit-code) since Wed 2015-09-23 11:12:01 UTC; 16s ago
      Process: 21505 ExecStop=/etc/init.d/supervisor stop (code=exited, status=0/SUCCESS)
      Process: 21511 ExecStart=/etc/init.d/supervisor start (code=exited, status=1/FAILURE)
    Sep 23 11:12:01 host supervisor[21511]: Starting supervisor:
    Sep 23 11:12:01 host systemd[1]: supervisor.service: control process exited, code=exited status=1
    Sep 23 11:12:01 host systemd[1]: Failed to start LSB: Start/stop supervisor.
    Sep 23 11:12:01 host systemd[1]: Unit supervisor.service entered failed state.

然而,监管程序或uwsgi日志中没有任何内容。 Supervisor 3.0使用此配置运行uwsgi :

[program:uwsgi]
stopsignal=QUIT
command = uwsgi --ini uwsgi.ini
directory = /dir/
environment=ENVIRONMENT=STAGING
logfile-maxbytes = 300MB

添加了stopsignal=QUIT,因为在停止时UWSGI会忽略默认信号(SIGTERM)并使用SIGKILL粗暴地杀死工作进程,从而留下孤儿进程。

有办法可以调查发生了什么吗?

编辑:

按照mnencia的建议尝试了以下命令:/etc/init.d/supervisor stop && while /etc/init.d/supervisor status ; do sleep 1; done && /etc/init.d/supervisor start 但它仍然有一半的时间失败。

 root@host:~# /etc/init.d/supervisor stop && while /etc/init.d/supervisor status ; do sleep 1; done && /etc/init.d/supervisor start
    [ ok ] Stopping supervisor (via systemctl): supervisor.service.
    ● supervisor.service - LSB: Start/stop supervisor
       Loaded: loaded (/etc/init.d/supervisor)
       Active: inactive (dead) since Tue 2015-11-24 13:04:32 UTC; 89ms ago
      Process: 23490 ExecStop=/etc/init.d/supervisor stop (code=exited, status=0/SUCCESS)
      Process: 23349 ExecStart=/etc/init.d/supervisor start (code=exited, status=0/SUCCESS)

    Nov 24 13:04:30 xxx supervisor[23349]: Starting supervisor: supervisord.
    Nov 24 13:04:30 xxx systemd[1]: Started LSB: Start/stop supervisor.
    Nov 24 13:04:32 xxx systemd[1]: Stopping LSB: Start/stop supervisor...
    Nov 24 13:04:32 xxx supervisor[23490]: Stopping supervisor: supervisord.
    Nov 24 13:04:32 xxx systemd[1]: Stopped LSB: Start/stop supervisor.
    [....] Starting supervisor (via systemctl): supervisor.serviceJob for supervisor.service failed. See 'systemctl status supervisor.service' and 'journalctl -xn' for details.
     failed!
    root@host:~# /etc/init.d/supervisor stop && while /etc/init.d/supervisor status ; do sleep 1; done && /etc/init.d/supervisor start
    [ ok ] Stopping supervisor (via systemctl): supervisor.service.
    ● supervisor.service - LSB: Start/stop supervisor
       Loaded: loaded (/etc/init.d/supervisor)
       Active: failed (Result: exit-code) since Tue 2015-11-24 13:04:32 UTC; 1s ago
      Process: 23490 ExecStop=/etc/init.d/supervisor stop (code=exited, status=0/SUCCESS)
      Process: 23526 ExecStart=/etc/init.d/supervisor start (code=exited, status=1/FAILURE)

Nov 24 13:04:32 xxx systemd[1]: supervisor.service: control process exited, code=exited status=1
Nov 24 13:04:32 xxx systemd[1]: Failed to start LSB: Start/stop supervisor.
Nov 24 13:04:32 xxx systemd[1]: Unit supervisor.service entered failed state.
Nov 24 13:04:32 xxx supervisor[23526]: Starting supervisor:
Nov 24 13:04:33 xxx systemd[1]: Stopped LSB: Start/stop supervisor.
[ ok ] Starting supervisor (via systemctl): supervisor.service.

在我看来,你实际上遇到了一个 bug。我已经在 Debian Bug 追踪系统 中开了一个关于这个问题的 bug。 - mnencia
我在我的回复中添加了一个解决方法。 - mnencia
2个回答

21

这不一定是supervisor的错误。我从您的systemctl status输出中看到,supervisor是通过sysv-init兼容层启动的,因此失败可能在/etc/init.d/supervisor脚本中。这可以解释为什么supervisord日志中没有错误。

要调试init脚本,最简单的方法是在该文件的第一个非注释指令中添加set -x,然后查看journalctl输出的脚本执行跟踪。

编辑:

我已经在Debian Sid上的测试系统上重现并调试了它。

问题在于supervisor init脚本的stop目标没有检查守护程序是否已经真正终止,而只是在进程存在时发送信号。如果守护程序进程需要一段时间才能关闭,则后续的start操作将由于正在死亡的守护程序进程被视为已经运行而失败。

我在Debian Bug Tracker上开了一个bug:http://bugs.debian.org/805920

解决方法:

您可以使用以下解决方法解决此问题:

/etc/init.d/supervisor force-stop && \
/etc/init.d/supervisor stop && \
/etc/init.d/supervisor start
  • force-stop将确保supervisord已经终止(在systemd之外)。
  • stop确保systemd知道它已被终止
  • start重新启动它

force-stop后面的stop是必需的,否则systemd将忽略任何后续的start请求。stopstart可以使用restart组合,但这里我将它们都放在一起以显示它们的工作原理。


这似乎解释了发生的情况。正如你建议的,我可以在问题得到修复之前使用"/etc/init.d/supervisor force-stop"和"/etc/init.d/supervisor start"来实现停止功能吗?尽管kill -9似乎有点过度杀伤力,但看起来还是可以接受的,当kill -15无效时。 - Paul K.
您可以在/etc/default/supervisor文件中设置DODTIME常量为足够长的时间,以确保不会发出kill -9命令。默认值为5秒。 - mnencia
它就像魔法般运作!10秒似乎足够优雅地终止100个繁忙的工作者。 - Paul K.
我有点太快了:force-stop->start不会启动uwgsi,我不知道为什么,直到我调用restart它才会启动。 - Paul K.
奇怪。也许你可以尝试使用 /etc/init.d/supervisor stop && while /etc/init.d/supervisor status ; do sleep 1; done && /etc/init.d/supervisor start。这应该与“重启”操作没有什么不同,只是在中间多等待一些时间。 - mnencia
显示剩余5条评论

0

我在Ubuntu 14.04中遇到了这个问题,尝试了来自Debian的最新initd脚本和@mnencia的解决方案,但它们对我没有起作用。force-stop解决方案无法杀死程序进程,它们在supervisord被杀死后仍然继续运行。

我的解决方案是修补supervisord并启动和重新启动initd脚本代码的部分。我不想猜测一个好的DODTIME,我希望它能够在旧的supervisor主进程死亡后立即启动,因此我添加了重试逻辑。请注意,它有点冗长,但如果您不喜欢这种行为,可以删除echo调用,并更改最大重试次数(此处设置为20)。

start)
    echo -n "Starting $DESC: "
    i=1
    until [ $i -ge 21 ]; do
        start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON -- $DAEMON_OPTS  && break
        echo -n -e "\nAlready running, old process still finishing? retrying ($i/20)..."
        let "i += 1"
        sleep 1
    done
sleep 1
    if running ; then
        echo "$NAME."
    else
        echo " ERROR."
    fi
;;
restart)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
    i=1
    until [ $i -ge 21 ]; do
        start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON -- $DAEMON_OPTS  && break
        echo -n -e "\nAlready running, old process still finishing? retrying ($i/20)..."
        let "i += 1"
        sleep 1
    done
    echo "$NAME."
    ;;

我还更改了哈希铃声(第一行),所以使用bash而不是sh,我想使用let

#! /bin/bash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接