我有一个连续运行的java进程,有时由于我尚未完全调试的原因,它会崩溃。因此,我还有一个 cron 作业,每 5 分钟查找一次进程,如果发现进程没有运行,它会调用一个脚本来重新启动它。
问题是,有时,检查脚本每隔一段时间就会得到一个误报——它认为进程没有运行,而实际上它正在运行。我还没有看到它何时执行此操作有任何一致性。但我确实需要一种完全万无一失的方法来检查进程是否正在运行。
我目前正在做的是这样的:
if ! pgrep -f '/path/to/XML2DB.jar -n' > /dev/null
then
nice -n 19 java -Xmx2024M -jar /path/to/XML2DB.jar -n > /dev/null 2>/dev/null &
echo "" | mail -s "$HOST: xml2db was found not running, is being started" [email protected]
fi
在 pgrep 之前,我们使用过,! ps ax | grep -v grep | grep "XML2DB.jar -n" > /dev/null
但这也会产生误报。
Linux 版本Scientific Linux SL release 3.0.9 (SL)
现在LSB Version
是 1.3。
提前致谢!
答案1
该ps ax | grep -v grep | grep "XML2DB.jar -n"
技术存在竞争条件:grep
实例可能会或可能不会及时启动以ps
查看它们,因此您会得到不准确的计数:请参阅这里和这里。您不是第一个在使用它时遇到麻烦的人。
我strace pgrep somepattern
在 RHEL 盒子上做了一个测试来了解pgrep
正在做什么。它统计 中的每个进程目录/proc
,并打开/proc/<PID>/cmdline
一些 PID,并读取内容,大概是为了与pgrep
命令行上给出的模式匹配。我在这里挥手,但我敢打赌那里也存在竞争条件。
对此唯一万无一失的解决方案是让 Java 进程尝试创建一个“锁定目录”。目录创建对于用户进程来说是原子的。如果锁定目录已经存在,则退出并显示错误消息,否则启动。创建后锁定目录,它应该将其 PID 写入锁定目录中的文件中。
您可以使用文件中的PID来检查Java程序是否正在运行kill -0 $(cat /whatever/lockdir/PIDfile)
- 如果进程不存在,kill
将以非零状态退出。
诀窍是在命令行上将 PID 传递给 Java 程序:
exec java blah blah -mypid $$
您仍然必须非常小心围绕锁定目录创建、解释kill -0
、 以及删除 PID 文件和锁定目录时出现的错误或异常,但使用任何其他方法都会遇到问题。
答案2
没有办法可靠且有效地检查不相关的进程是否正在运行:竞争条件始终是可能的。即使您找到一种方法来检测您感兴趣的进程是否正在运行,它也可能在您看到它后立即被杀死,或者相反,它可能在您错过它后立即启动。
如果您控制程序或其运行方式,则可以使其保留独特的资源,例如文件锁。但是,如果您控制程序的调用方式,则可以使用一种更简单的方法来跟踪它:从其父级监视它。当一个进程的子进程死亡时,它就会被通知。
确保进程始终运行的最简单方法是循环重新启动它。
# sleep 1 avoids a tight loop if the process systematically fails to start
while sleep 1; do
nice …
ret=$?
if [ $ret -le 127 ]; then
msg="… exited with status $ret"
else
msg="… exited on signal $((ret-128))"
esac
mail -s "$msg" "$USER"
done
有更强大、更强大的监控软件。看如何以自动化的方式对我的服务进行适当的监控?那么,如果发生崩溃,它会自动重新启动吗?