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

时间:2013-09-13 09:59:18

标签: bash process-management

Greg's Wiki有一个非常简单的例子,说明如何让服务器运行s.t.如果它退出,它会立即重新启动:

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

但是你想让N服务器保持运行的位置,s.t。如果一个失败,所有应该重新启动? 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状态,有没有办法用旧系统执行此操作?

2 个答案:

答案 0 :(得分:0)

以下是我提出的方法,基于Greg's Wiki和#bash在irc.freenode.net上的一些帮助:

#!/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放在自己的process group中来避免陷阱:

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

答案 1 :(得分: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。