Bash:如何保持N个程序运行,如果其中一个程序失败,则重新启动所有程序?
下面是一个非常简单的示例,说明如何保持服务器运行s.t。如果服务器退出,它将立即重新启动: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
#!/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