Upstart 跟踪错误的进程 PID - 不会重生

Upstart 跟踪错误的进程 PID - 不会重生

我最初是在 StackOverflow 上问这个问题的。后来我意识到这里可能是一个更好的地方。

我已设置 bluepill 来监控我的 delayed_job 进程。(Ruby On Rails 应用程序)

使用 Ubuntu 12.10。

我正在使用 Ubuntu 的 启动并监控 bluepill 服务本身upstart。我的 upstart 配置如下 ( /etc/init/bluepill.conf)。

description "Start up the bluepill service"

start on runlevel [2]
stop on runlevel [016]

expect daemon
exec sudo /home/deploy/.rvm/wrappers/<app_name>/bluepill load /home/deploy/websites/<app_name>/current/config/server/staging/delayed_job.bluepill

# Restart the process if it dies with a signal
# or exit code not given by the 'normal exit' stanza.
respawn

我也尝试过用expect fork代替expect daemon。我也尝试过expect...完全删除该行。

当机器启动时,bluepill启动正常。

$ ps aux | grep blue
root      1154  0.6  0.8 206416 17372 ?        Sl   21:19   0:00 bluepilld: <app_name>

此处 bluepill 进程的 PID 为 1154。但upstart似乎跟踪的是错误的 PID。它跟踪的是一个不存在的 PID。

$ initctl status bluepill
bluepill start/running, process 990

sudo我认为它正在跟踪启动 bluepill 进程的进程的 PID 。

如果我使用强制终止 bluepill,这将阻止 bluepill 进程重生kill -9

此外,我认为由于跟踪了错误的 PID,重启/关机就会挂起,每次我都必须硬重置机器。

这可能是什么问题?

更新

截至今天(2015 年 5 月 3 日),Ubuntu 14.04.2 上的问题仍然存在。

问题不是因为使用 sudo。我不再使用 sudo。我更新的 upstart 配置如下:

description "Start up the bluepill service"

start on runlevel [2]
stop on runlevel [016]

# Restart the process if it dies with a signal
# or exit code not given by the 'normal exit' stanza.
respawn

# Give up if restart occurs 10 times in 90 seconds.
respawn limit 10 90

expect daemon

script
    shared_path=/home/deploy/websites/some_app/shared

    bluepill load $shared_path/config/delayed_job.bluepill
end script

当机器启动时,程序加载正常。但 upstart 仍然跟踪错误的 PID,如上所述。

评论中提到的解决方法可能会解决挂起问题。不过我还没有尝试过。

答案1

很晚了,但希望这可以为其他用户提供帮助。

forkupstart 中有一个记录在案的错误,如果你在 upstart 配置中指定了不正确的节,它可能会导致 initctl 跟踪错误的 PID :https://bugs.launchpad.net/upstart/+bug/406397

实际情况是,upstart 检查fork节并确定在选择受控程序的“真实”PID 之前应检查多少个分叉进程。如果您指定expect forkexpect daemon但程序分叉次数不够,start则会挂起。另一方面,如果您的进程分叉次数过多,initctl则会跟踪错误的 PID。理论上,应该记录在此新贵食谱的一部分但是正如您所见,在这种情况下,有一个 PID 与被终止的进程相关联,但不应该有。

这个含义在 bugtracker 评论中已经解释过了,但我将在这里总结一下:除了initctl无法停止守护进程并陷入未记录/非法状态之外<service> start/killed, process <pid>,如果属于该 PID 的进程停止(通常会停止),那么该 PID 将被释放以供系统重新使用。

如果您发出initctl stop <service>service <service> stop,则initctl下次出现该 PID 时,它将被终止。这意味着,如果您在犯此错误后不重新启动,则下一个使用该 PID 的进程将被立即终止,initctl即使它不是守护进程。它可能像 一样简单,cat也可能像 一样复杂ffmpeg,您将很难弄清楚为什么您的软件包在某些常规操作中崩溃了。

因此,问题在于expect您为守护进程实际进行的分叉数量指定了错误的选项。他们说有一个 upstart 重写版本可以解决这个问题,但从 upstart 1.8(最新的 Ubuntu 13.04/2014 年 1 月)开始,这个问题仍然存在。

由于您使用过expect daemon并遇到了这个问题,我建议您尝试一下expect fork

编辑:这是一个与 Ubuntu BASH 兼容的脚本(原著:韦德·菲茨帕特里克修改为使用 Ubuntu sleep)会生成进程,直到可用进程 ID 地址空间耗尽,此时它会从 0 开始,并一直运行到“卡住”的 PID。然后在initctl挂起的 PID 处生成一个进程,并将initctl其杀死并重置。

#!/bin/bash

# usage: sh /tmp/upstart_fix.sh <pid>

sleep 0.001 &
firstPID=$!
#first lets exhaust the space
while (( $! >= $firstPID ))
do
    sleep 0.001 &
done

# [ will use testPID itself, we want to use the next pid
declare -i testPID
testPID=$(($1 - 1))
while (( $! < $testPID ))
do
    sleep 0.001 &
done

# fork a background process then die so init reaps its pid
sleep 3 &
echo "Init will reap PID=$!"
kill -9 $$
# EOF

答案2

对于提供的示例:

$ initctl status bluepill
bluepill start/running, process 990

对我来说一个快速的解决方案是:

# If upstart gets stuck for some job in stop/killed state
export PID=990
cd /usr/local/bin
wget https://raw.github.com/ion1/workaround-upstart-snafu/master/workaround-upstart-snafu
chmod +x workaround-upstart-snafu
./workaround-upstart-snafu $PID

来源:https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582745#37

我希望这会有所帮助。其他答案中解释了发生了什么。

答案3

除非你正在运行Upstart 用户级工作或者使用 setuid 节- 那么你的工作就是以 root 身份运行。

既然 Upstart 已经以 root 身份运行,为什么还需要在您的exec节中使用 sudo?

在节中使用sudo或给我带来了与您在此处描述的相同的问题。suexec

通常我会经历第 1 项,或者第 1 项和第 2 项:

  1. upstart 遵循了错误的 PID
  2. 当我尝试停止该进程时,upstart 挂起了

当然,另外你还必须让expect节反映出正确的叉数。

YMMV,但对我来说:

  • 在节中使用 sudo 或 suexec并指定正确的 fork 数量通常会导致上述情况 1。
  • 指定不正确的 fork 数量(带有或不带有 sudo/su exec)会导致上述情况 1 和 2。

相关内容