Bash:如何保持N个程序运行,如果其中一个程序失败,则重新启动所有程序?

Bash:如何保持N个程序运行,如果其中一个程序失败,则重新启动所有程序?,bash,process-management,Bash,Process Management,下面是一个非常简单的示例,说明如何保持服务器运行s.t。如果服务器退出,它将立即重新启动: #!/bin/sh while :; do /my/game/server -foo -bar -baz >> /var/log/mygameserver 2>&1 done 但是你想让N台服务器在哪里运行呢,s.t.如果其中一台出现故障,所有服务器都应该重新启动?说Bash4.3会让我做 while :; do server1 & p1=$! s

下面是一个非常简单的示例,说明如何保持服务器运行s.t。如果服务器退出,它将立即重新启动:

#!/bin/sh
while :; do
   /my/game/server -foo -bar -baz >> /var/log/mygameserver 2>&1
done
但是你想让N台服务器在哪里运行呢,s.t.如果其中一台出现故障,所有服务器都应该重新启动?说Bash4.3会让我做

while :; do
    server1 & p1=$!
    server2 & p2=$!
    wait -n $p1 $p2 # wait until at least one exits
    kill $p1 $p2
done

但是4.3仍然是alpha版本,有没有办法在较旧的系统上做到这一点呢?

以下是我根据irc.freenode.net上的#bash提供的一些帮助提出的方法:

#!/bin/bash
trap 'rm -f manager; kill 0' EXIT
mkfifo manager
declare -A pids
restart () {
    # assuming your servers/daemons are programs "a" and "b"
    [[ -n ${pids[a]} ]] && kill "${pids[a]}"
    [[ -n ${pids[b]} ]] && kill "${pids[b]}"
    run_and_tell manager a & pids[a]=$!
    run_and_tell manager b & pids[b]=$!
}
restart
while :; do
  read < manager
  restart
done
虽然不如bash4.3版本好,但它似乎可以工作(例如,在run_和_-tell中使用“sleep 9999”进行测试)。一个烦恼是我必须
在runner中捕获'kill$pid'退出
,而且似乎我必须在$prog中执行同样的操作,以确保在其父级被杀死时杀死它

这里有一个替代版本,通过将run_和_tell放在自己的版本中,可以避免陷阱:


最简单的方法是为每个间隔手动检查它们:

#!/bin/bash

function check_if_all_active {
    local p
    for p in "$@"; do
        kill -s 0 "$p" &>/dev/null || return 1
    done
    return 0
}

while :; do
    pids=()
    server1 & pids+=("$!")
    server2 & pids+=("$!")
    while check_if_all_active "${pids[@]}"; do
        sleep 1s  ## Can be longer.
    done
    kill -s SIGTERM "${pids[@]}" &>/dev/null
done

你也可以考虑其他的信号来停止你的进程,比如SypUp或Sigabt。

睡眠/轮询方法的一个可能的问题是,如果你希望管理者确保没有一个用户输入到服务器1 / Serv2等时,其中一个就死了;睡眠1秒钟可能会导致比赛状态(特别是如果死亡通常发生在高负荷情况下)。阅读
#!/bin/bash
# The trap now needs to kill all created process groups:
trap 'rm -f manager; kill 0; kill ${pids[a]} ${pids[b]}' EXIT
mkfifo manager
declare -A pids
restart () {
    # assuming servers/daemons are programs "a" and "b":
    [[ -n ${pids[a]} ]] && kill -TERM -"${pids[a]}"
    [[ -n ${pids[b]} ]] && kill -TERM -"${pids[b]}"
    setsid ./run_and_tell manager a & pids[a]=$!
    setsid ./run_and_tell manager b & pids[b]=$!
}
restart
while :; do
  read < manager
  restart
done
#!/bin/bash
manager=$1
prog=$2
$prog
echo >"$manager"
#!/bin/bash

function check_if_all_active {
    local p
    for p in "$@"; do
        kill -s 0 "$p" &>/dev/null || return 1
    done
    return 0
}

while :; do
    pids=()
    server1 & pids+=("$!")
    server2 & pids+=("$!")
    while check_if_all_active "${pids[@]}"; do
        sleep 1s  ## Can be longer.
    done
    kill -s SIGTERM "${pids[@]}" &>/dev/null
done