代码之家  ›  专栏  ›  技术社区  ›  Tom Gruff

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

  •  197
  • Tom Gruff  · 技术社区  · 17 年前

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

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

    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
    
    7 回复  |  直到 10 年前
        1
  •  700
  •   Community Mohan Dere    9 年前

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

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

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

    until myserver; do
        echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
        sleep 1
    done
    

    上面的bash代码运行 myserver 在一个 until 环第一行开始 并等待它结束。当它结束时, 直到 0 0 直到 将运行循环体,它在STDERR上发出错误消息并重新启动循环(返回到第1行) .

    我们为什么要等一会儿?因为如果启动顺序有问题 它会立即崩溃,你会有一个非常密集的循环,不断地重新启动和崩溃在你的手上。这个 sleep 1 消除了压力。

    我的服务器 @reboot 规则使用打开您的cron规则 crontab :

    crontab -e
    

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

    @reboot /usr/local/bin/myservermonitor
    

    我的服务器


    编辑

    让我补充一下原因 使用PID文件。虽然他们很受欢迎;它们也有很大的缺陷,你没有理由不按正确的方式去做。

    考虑一下:

      • /etc/init.d/foo start :开始 foo 是的 /var/run/foo.pid
      • 过了一会儿: 不知怎么死了。
      • 一段时间后:任何开始的随机过程(称之为 bar )需要一个随机PID,想象一下 这是老PID。
      • 你注意到了吗 /etc/init.d/foo/restart 阅读 /var/run/foo.pid 酒吧 ,认为是 ,杀死它,开始新的生活
    1. PID文件会过时。您需要过于复杂(或者我应该说,非常复杂)的逻辑来检查PID文件是否过时,并且任何此类逻辑都会再次受到攻击 1. .

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

    Are PID-files still flawed when doing it 'right'?

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

    1. 这会导致很多误报。拿 ps aux | grep PID 例如,现在想象有人启动一个进程,在某个地方使用一个数字作为参数,该参数恰好与启动守护进程时使用的PID相同!想象一下,两个人开始一个X会话,而你却用X来杀死你的会话。只是各种各样的不好。

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

        2
  •  42
  •   Eric    8 年前

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

    或者做一个简单的脚本:

    while true
    do
    /your/script
    sleep 1
    done
    
        3
  •  9
  •   Teddy Markov    10 年前

    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
  •  6
  •   clofresh    17 年前

    从文档中: 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
  •  5
  •   soulmerge    17 年前
    if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
        restart_process
        # Write PIDFILE
        echo $! >$PIDFILE
    fi
    
        6
  •  2
  •   Daniel Bradley    7 年前

    具体来说,这组命令包括“不断运行一个”,这似乎正是所需要的。

    从手册页:

        7
  •  2
  •   Benyamin Jafari    5 年前

    一致:

    while true; do <your-bash-snippet> && break; done
    
    

    例如

    while true; do openconnect x.x.x.x:xxxx && break; done
    
    
        8
  •  1
  •   Kevin Wright    16 年前

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

    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,这要多得多 分布之间的一致性比
    • $INSTALLATION 包含足够多的过程路径,这是完全明确的

    这个脚本实际上用于关闭tomcat的一个正在运行的实例,我想在命令行关闭(并等待),因此我不想将它作为子进程启动。

        9
  •  1
  •   BitDEVil2K16    6 年前

    我将其用于我的npm流程

    #!/bin/bash
    for (( ; ; ))
    do
    date +"%T"
    echo Start Process
    cd /toFolder
    sudo process
    date +"%T"
    echo Crash
    sleep 1
    done