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

如果进程死亡,如何编写bash脚本来重新启动进程?,bash,scripting,cron,Bash,Scripting,Cron,我有一个python脚本,它将检查队列并对每个项目执行操作: # checkqueue.py while True: check_queue() do_something() 如何编写一个bash脚本来检查它是否正在运行,如果没有,则启动它。大致如下伪代码(或者它应该执行类似于ps | grep?)的操作): 我将从crontab中调用它: # crontab */5 * * * * /path/to/keepalivescript.sh 最简单的方法是在文件中使用flock。在Py

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

# checkqueue.py
while True:
  check_queue()
  do_something()
如何编写一个bash脚本来检查它是否正在运行,如果没有,则启动它。大致如下伪代码(或者它应该执行类似于
ps | grep
?)的操作):

我将从crontab中调用它:

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

最简单的方法是在文件中使用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
当然,您不必进行测试,因为如果它已经在运行,并且您重新启动它,它将退出并显示“其他实例已经在运行”


当进程终止时,它的所有文件描述符都将关闭,所有锁将自动删除。

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

if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
    restart_process
    # Write PIDFILE
    echo $! >$PIDFILE
fi
从文档中:

使用pidfile/var/run/checkqueue.pid检查process checkqueue.py 如果更改了pid,则执行“checkqueue\u restart.sh” 您还可以将monit配置为在重新启动时向您发送电子邮件。

查看monit()。它处理脚本的启动、停止和重新启动,并可以执行运行状况检查,必要时还可以重新启动

或者做一个简单的脚本:

while true
do
/your/script
sleep 1
done

避免使用PID文件、cron或任何其他试图评估不是其子进程的进程

有一个很好的理由可以解释为什么在UNIX中,您只能照看您的孩子。任何试图解决有缺陷且存在漏洞的方法(ps解析、pgrep、存储PID等)。只要说“不”

相反,您需要监视流程的流程成为流程的父级。这是什么意思?这意味着只有启动流程的流程才能可靠地等待其结束。在bash中,这绝对是微不足道的

until myserver; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done
上面的bash代码在
循环中运行
myserver
,直到
循环结束。第一行启动myserver并等待它结束。当它结束时,
直到
检查其退出状态。如果退出状态为
0
,则表示它正常结束(这意味着您要求它以某种方式关闭,但它成功地关闭了)。在这种情况下,我们不想重新启动它(我们只是要求它关闭!)。如果退出状态不是
0
until
将运行循环体,循环体将在STDERR上发出错误消息,并在1秒后重新启动循环(返回第1行)

我们为什么要等一会儿?因为如果
myserver
的启动顺序出现问题,并且立即崩溃,那么您将有一个非常密集的不断重启和崩溃循环。
sleep 1
消除了这方面的压力

现在,您需要做的就是启动这个bash脚本(可能是异步的),它将监视
myserver
,并根据需要重新启动它。如果要在引导时启动监视器(使服务器“存活”重新引导),可以使用
@reboot
规则在用户的cron(1)中安排它。使用
crontab
打开您的cron规则:

crontab -e
然后添加一条规则以启动监视器脚本:

@reboot /usr/local/bin/myservermonitor

或者;查看inittab(5)和/etc/inittab。您可以在其中添加一行,使
myserver
在某个init级别启动并自动重新启动


编辑

让我添加一些关于为什么不使用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
      ,检查它是否还活着,找到
      ,认为它是
      foo
      ,杀死它,启动一个新的
      foo
  • PID文件会过时。您需要过于复杂(或者我应该说,非常复杂)的逻辑来检查PID文件是否过时,并且任何此类逻辑都会再次受到
    1.
    的攻击

  • 如果您甚至没有写访问权限或处于只读环境中,该怎么办

  • 这是毫无意义的过度复杂化;看看我上面的例子有多简单。根本不需要把这件事复杂化

  • 另见:

    顺便说一下比PID文件更糟糕的是解析
    ps
    永远不要这样做

  • ps
    非常不适合携带。而您几乎可以在每个UNIX系统上找到它;如果您想要非标准输出,它的参数会有很大的不同。标准输出仅用于人类消费,不用于脚本解析
  • 解析
    ps
    会导致大量误报。以
    ps aux | grep PID
    为例,现在想象有人启动一个进程,在某个地方使用一个数字作为参数,该参数恰好与启动守护进程时使用的PID相同!想象一下,两个人开始一个X会话,而你却用X来杀死你的会话。只是各种各样的不好

  • 如果你不想自己管理这个过程;有一些非常好的系统可以作为流程的监视器。例如,查看。

    我在许多服务器上成功地使用了以下脚本:

    pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
    echo $INSTALLATION found at PID $pid 
    while [ -e /proc/$pid ]; do sleep 0.1; done
    
    注:

    • 它正在寻找一个java进程,所以我 可以使用jps,这要多得多 分布之间的一致性比 ps
    • $INSTALLATION
      包含了足够多的进程路径,这是非常明确的
    • 在等待进程结束时使用睡眠,避免占用资源:)@reboot /usr/local/bin/myservermonitor
    pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
    echo $INSTALLATION found at PID $pid 
    while [ -e /proc/$pid ]; do sleep 0.1; done
    
    #!/bin/bash
    for (( ; ; ))
    do
    date +"%T"
    echo Start Process
    cd /toFolder
    sudo process
    date +"%T"
    echo Crash
    sleep 1
    done