当前位置:  开发笔记 > 编程语言 > 正文

如果进程死了,如何编写bash脚本来重启?

如何解决《如果进程死了,如何编写bash脚本来重启?》经验,为你挑选了5个好方法。

我有一个python脚本,它将检查队列并对每个项目执行操作:

# checkqueue.py
while True:
  check_queue()
  do_something()

如何编写一个bash脚本来检查它是否正在运行,如果没有,则启动它.大概下面的伪代码(或者它应该做类似的事情ps | grep?):

# keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile

我将从crontab中调用它:

# crontab
*/5 * * * * /path/to/keepalivescript.sh

lhunath.. 604

避免使用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,写入fooPID/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杀死你的.这只是各种各样的坏事.

如果您不想自己管理流程; 有一些非常好的系统可以作为您的流程的监控器.例如,看看runit.



1> lhunath..:

避免使用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,写入fooPID/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杀死你的.这只是各种各样的坏事.

如果您不想自己管理流程; 有一些非常好的系统可以作为您的流程的监控器.例如,看看runit.


可以相信我只是*看到这个答案.非常感谢!
@orschiro程序运行时没有资源消耗.如果它在启动时立即存在,则连续休眠,睡眠1的资源消耗仍然完全可以忽略不计.
@TomášZato,您可以执行上述循环,而无需测试进程的退出代码“ true”;做我的过程; 已完成”,但请注意,现在无法停止该过程。
@ SergeyP.akaazure迫使父母在bash退出时杀死孩子的唯一方法是将孩子变成一份工作并发信号:"陷阱"杀$(jobs -p)'退出; 直到myserver&wait; 做睡觉1; done`

2> Bernd..:

看看monit(http://mmonit.com/monit/).它处理脚本的启动,停止和重新启动,并且可以执行运行状况检查以及必要时重新启动.

或者做一个简单的脚本:

while true
do
/your/script
sleep 1
done


Monit正是您所寻找的.
"1"不起作用.你需要"while [1]"或"while true"或"while:".请参阅https://unix.stackexchange.com/questions/367108/what-does-while-mean

3> vartec..:

最简单的方法是在文件中使用flock.在Python脚本中你会这样做

lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0): 
   sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()

在shell中,您可以实际测试它是否正在运行:

if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then 
   echo 'it's not running'
   restart.
else
   echo -n 'it's already running with PID '
   cat /tmp/script.lock
fi

但是当然你不必测试,因为如果它已经运行并且你重新启动它,它将退出 'other instance already running'

当进程死亡时,它的所有文件描述符都将被关闭,并自动删除所有锁.



4> clofresh..:

您应该使用monit,这是一个标准的unix工具,可以监视系统上的不同内容并做出相应的反应.

来自文档:http://mmonit.com/monit/documentation/monit.html#pid_testing

check process checkqueue.py with pidfile /var/run/checkqueue.pid
       if changed pid then exec "checkqueue_restart.sh"

您还可以配置monit,以便在重新启动时通过电子邮件发送给您.



5> soulmerge..:
if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
    restart_process
    # Write PIDFILE
    echo $! >$PIDFILE
fi


在真正繁忙的服务器上,PID可能会在您检查之前被回收.
推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有