避免使用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
,until
将运行循环主体,该循环主体将在STDERR上发出错误消息,并在1秒后重新启动循环(返回第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
已经消失了:/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拼命杀死了您的X。只是种种不好。
如果您不想自己管理流程;有一些非常好的系统可以充当您的过程的监视器。例如,看看runit。