避免使用 PID 文件、crons 或任何其他试图评估不是其子进程的进程。
在 UNIX 中,您只能等待您的孩子,这是有充分理由的。任何试图解决这个问题的方法(ps 解析、pgrep、存储 PID,...)都是有缺陷的,并且存在漏洞。只是说不。
相反,您需要将监控您的进程的进程作为该进程的父进程。这是什么意思?这意味着只有启动你的进程的进程才能可靠地等待它结束。在 bash 中,这绝对是微不足道的。
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
上面这段 bash 代码循环运行myserver
。until
第一行开始myserver
并等待它结束。当它结束时,until
检查它的退出状态。如果退出状态为0
,则表示它正常结束(这意味着您要求它以某种方式关闭,并且它成功地关闭了)。在这种情况下,我们不想重新启动它(我们只是要求它关闭!)。如果退出状态不是 0
,将运行循环体,它会在 STDERR 上发出错误消息并在 1 秒后until
重新启动循环(回到第 1 行)。
我们为什么要等一秒钟?因为如果启动顺序有问题myserver
,它会立即崩溃,你将有一个非常密集的循环,不断重启和崩溃。消除了sleep 1
压力。
现在您需要做的就是启动这个 bash 脚本(可能是异步的),它会监控myserver
并在必要时重新启动它。如果您想在启动时启动监视器(使服务器“存活”重新启动),您可以使用@reboot
规则将其安排在用户的 cron(1) 中。使用以下命令打开您的 cron 规则crontab
:
crontab -e
然后添加一个规则来启动你的监控脚本:
@reboot /usr/local/bin/myservermonitor
或者; 查看 inittab(5) 和 /etc/inittab。您可以在其中添加一行以myserver
从某个初始级别开始并自动重生。
编辑。
让我添加一些关于为什么不使用 PID 文件的信息。虽然它们很受欢迎;他们也有很大的缺陷,你没有理由不以正确的方式去做。
考虑一下:
PID回收(杀错进程):
/etc/init.d/foo start
: 开始foo
,将foo
PID写入/var/run/foo.pid
- 过了一会儿:
foo
不知何故死去。
- 过了一会儿:任何开始的随机进程(称为它
bar
)都需要一个随机 PID,想象一下它使用foo
的是旧的 PID。
- 你注意到
foo
's''''''''''''''''''''''''''''''''''''''''''''''/etc/init.d/foo/restart
读取,检查它/var/run/foo.pid
是否还活着,找到' ' ''''''''''''''''''''''''''''bar
foo
foo
PID 文件过时。您需要过于复杂(或者我应该说,不平凡)的逻辑来检查 PID 文件是否过时,并且任何此类逻辑再次容易受到1.
.
如果您甚至没有写访问权限或处于只读环境中怎么办?
这是毫无意义的过度复杂化;看看我上面的例子是多么简单。完全没有必要把它复杂化。
另请参阅:“正确”执行时,PID 文件是否仍然存在缺陷?
顺便一提; 比 PID 文件更糟糕的是解析ps
! 永远不要这样做。
ps
非常不便携。虽然您几乎可以在每个 UNIX 系统上找到它;如果您想要非标准输出,它的参数会有很大差异。标准输出仅供人类使用,不能用于脚本解析!
- 解析
ps
会导致很多误报。举ps aux | grep PID
个例子,现在想象有人以某个地方的数字作为参数启动一个进程,该参数恰好与您盯着守护程序使用的 PID 相同!想象一下,两个人开始一个 X 会话,而你正在寻找 X 来杀死你的会话。这只是各种各样的坏事。
如果您不想自己管理流程;有一些非常好的系统可以作为您流程的监控器。例如,查看runit。