避免使用PID文件、cron或任何其他试图判断非其子进程的文件.
有一个很好的理由可以解释为什么在UNIX中,您只能照顾您的子元素.任何方法(ps解析、pgrep、存储PID等)它试图解决有缺陷且存在巨大漏洞的问题.就说no吧.
相反,您需要监视流程的流程成为流程的父级.这是什么意思?这意味着只有starts个进程可以可靠地等待进程结束.在bash中,这绝对是微不足道的.
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
上面的bash代码在until
循环中运行myserver
次.第一行从myserver
开始,等待它结束.当它结束时,until
判断其退出状态.如果退出状态为0
,则意味着它优雅地结束了(这意味着你要求它以某种方式关闭,它成功地关闭了).在这种情况下,我们不想重新启动它(我们只是要求它关闭!).如果退出状态为not 0
,until
将运行循环体,它在STDERR上发出错误消息并重新启动循环(返回到第1行)after 1 second.
我们为什么要等一会儿?因为如果myserver
的启动顺序出了问题,它会立即崩溃,你会有一个非常密集的不断重启和崩溃循环.sleep 1
消除了压力.
现在,您需要做的就是启动这个bash脚本(可能是异步的),它将监视myserver
,并根据需要重新启动它.如果您想在 bootstrap 时启动监视器(使服务器"存活"重新 bootstrap ),可以使用@reboot
规则在用户的cron(1)中安排它.用crontab
打开你的cron规则:
crontab -e
然后添加一条规则来启动监视器脚本:
@reboot /usr/local/bin/myservermonitor
或者;看看inittab(5)和/etc/inittab.您可以在其中添加一行,使其在某个初始级别有myserver
个开始,并自动重新启动.
编辑
让我添加一些关于为什么要使用PID文件的信息.虽然他们很受欢迎;它们也有很大的缺陷,你没有理由不按正确的方式go 做.
考虑一下:
PID回收(终止错误的流程):
/etc/init.d/foo start
:启动foo
,将foo
的PID写入/var/run/foo.pid
- 过了一会儿,
foo
人不知怎么死了.
- 一段时间后:任何启动的随机进程(称为
bar
)都需要一个随机PID,想象一下它需要foo
的旧PID.
- 你注意到
foo
已经消失了:/etc/init.d/foo/restart
读取/var/run/foo.pid
,判断它是否还活着,找到bar
,认为它是foo
,杀死它,开始一个新的foo
.
PID文件会过时.您需要过于复杂(或者我应该说,非常复杂)的逻辑来判断PID文件是否过时,任何这样的逻辑都会再次受到1.
的攻击.
如果您甚至没有写访问权限,或者处于只读环境中,该怎么办?
这是毫无意义的过度复杂;看看我上面的例子有多简单.根本没必要让这件事复杂化.
See also: Are PID-files still flawed when doing it 'right'?
顺便说一句永远不要这样做.
ps
是很不合适的.而在几乎所有的UNIX系统上都可以找到它;如果您想要非标准输出,它的参数会有很大差异.标准输出仅用于人类消费,不用于脚本解析!
- 解析
ps
会导致很多误报.以ps aux | grep PID
为例,现在想象有人在某个地方启动一个进程,并以一个数字作为参数,该参数恰好与启动守护进程时使用的PID相同!想象一下,两个人开始了一个X会话,而你却大喊X来杀死你的X会话.只是各种各样的不好.
如果你不想自己管理这个过程;有一些非常好的系统可以作为流程的监视器.例如,看看runit.