0

Greg 的 Wiki有一个非常简单的示例,说明如何保持服务器运行 st 如果它退出,它会立即重新启动:

#!/bin/sh
while :; do
   /my/game/server -foo -bar -baz >> /var/log/mygameserver 2>&1
done

但是你想让 N 台服务器保持在哪里运行,如果一台服务器出现故障,所有服务器都应该重新启动吗?http://wiki.bash-hackers.org/scripting/bashchanges说 bash 4.3 会让我做

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

但是 4.3 仍处于 alpha 阶段,有没有办法用旧系统做到这一点?

4

2 回答 2

0

这是我根据Greg 的 Wiki和 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

和 run_and_tell:

#!/bin/bash
trap 'kill $pid' EXIT
manager=$1
prog=$2
$prog & pid=$!
wait $pid
echo >"$manager"

不如 bash 4.3 版本好,但它似乎可以工作(例如在 run_and_tell 中使用“sleep 9999”进行测试)。一个烦恼是我必须trap 'kill $pid' EXIT在跑步者中,而且似乎我必须在 $prog 中做同样的事情,以确保它在其父母被杀死时被杀死。

这是一个避免陷入困境的替代版本,方法是将 run_and_tell 放在自己的进程组中

#!/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

并且 run_and_tell 变成了:

#!/bin/bash
manager=$1
prog=$2
$prog
echo >"$manager"
于 2013-09-13T09:59:17.693 回答
0

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

#!/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

您还可以考虑使用其他信号来停止您的进程,例如 SIGHUP 或 SIGABRT。

于 2013-09-13T11:02:15.913 回答