守护进程崩溃,但新贵认为它还活着

守护进程崩溃,但新贵认为它还活着

我遇到了以下问题:我们有一个由 bash 脚本启动的 Java 应用程序。此应用程序应作为守护进程运行,因此我们有一个 upstart-job 来启动它。

start on runlevel [2345]                    
stop on runlevel [!2345]                    

#tell upstart we will fork later, so it will mangage the pids. 
 expect fork


#If the daemon stoppes unexpectedly, restart it! 
respawn
script
  #The framework will only work, if we start it from this directory.
  cd /usr/lib/app-dir
  nohup ./appStartScript.sh &> /dev/null &

  #send an upstart event, in case we will chain this job later
  emit app_running                         
end script

有时,应用程序会停止工作。没有 .hprof 文件,也没有通常在 VM 崩溃时创建的 hserr 文件。Upstart 报告应用程序正在运行,

appDeamon start/running, process 1131

但 PID 没有列在ps-aux。(此外,upstart 无法使用停止应用程序守护进程

我想知道:a)为什么upstart没有意识到应用程序已经崩溃?b)是否有可能强制upstart重新启动应用程序,即使具有给定pid的进程不再存在?(到目前为止,我们需要重新启动整个服务器。)

我们的系统是 Ubuntu Linux 10.04.1 LTS。

答案1

守护进程通常会发生以下情况:

  1. Upstart 在前台运行可执行文件
  2. 该程序加载其配置文件,检查它,执行各种设置操作(如打开监听端口)。
  3. 如果上一步失败,程序将退出,并且 upstart 将获得一个非零的退出代码,从而知道它失败了
  4. 如果步骤 2 没有失败,程序现在会分叉,本质上会创建它的两个副本
  5. Upstart 最初执行的进程现在以零退出代码退出,表明它已成功
  6. 分叉的进程继续运行并完成应用程序的实际工作

问题是 Java 没有提供分叉机制,因此这种久经考验的模式无法正确实现。执行 Java 守护进程时,您被迫立即将进程置于后台(即&脚本中的符号)。Upstart 本质上是启动进程,然后立即忘记它——进程无法向 Upstart 指示它是否成功启动。

解决这个问题的唯一方法是启动该进程,将其置于后台,然后检查它是否仍在运行,以确定它是否成功。当然,关键是确定什么时候检查它是否仍在运行。简单的解决方案如下:

#!/bin/sh
java MyClass >/dev/null 2>&1 &
PID=$!
sleep 3
if kill -0 $PID; then
    exit 0
else
    exit 1
fi

还有更多精心策划确定何时检查进程,例如让程序在完成启动例程时关闭 stdout 和 stderr 或创建其 PID 文件,并在启动脚本中等待这些事件。

对于您来说,最简单的解决方案是将 Upstart 脚本修改为如下所示的内容:

script
    cd /usr/lib/app-dir
    nohup ./appStartScript.sh &> /dev/null &
    PID=$!
    sleep 3
    if kill -0 $PID; then
        emit app_running                         
        exit 0
    else
        exit 1
    fi
end script

答案2

为什么您的应用程序需要通过脚本启动bash?Upstart 需要知道您的应用程序分叉了多少次。您已告诉它它不会分叉(因为您未指定“ expect”节),但您还是分叉了(因为您在脚本部分指定了“ &”。因此,Upstart 无法跟踪 PID。

请参见:

相关内容