0

(ノード)開発サーバーを起動するスクリプトをまとめようとしています。それを受け取るたびにSIGHUP、サーバーを再起動する必要があります。

サーバーを生成し、シャットダウンし、サーバーを再起動するところまで行きましたSIGHUP。しかしwait、スポーン コードで使用しているため、SIGHUPハンドラーが実際に戻ることはなく、シグナルが再び発生することはありません。

これが私のスクリプトの簡素化されたバージョンです:

SERVER_PID=""

start_server() {
    npm start &
    SERVER_PID=$!
    wait $SERVER_PID
}
terminate_server() {
    [ ! "xSERVER_PID" = "X" ] && kill -SIGTERM $SERVER_PID
    SERVER_PID=""
}
refresh_server() {
    terminate_server
    start_server
}

trap refresh_server SIGHUP
start_server

前述したように、サーバーを正常に起動し、最初の で期待どおりに動作しSIGHUPますが、 inrefresh_serverのために返されないため、後続のシグナルはアクションをトリガーしません。waitstart_server

今のところ、waitinを取り出しstart_server、最後に無限の「while-true-sleep」ループを追加することで問題を解決しました ( への最初の呼び出しの後start_server)。私が達成しようとしていることを達成します。また、スリープ ループ アプローチから生じる信号トリガーの遅延も嫌いです。

4

3 に答える 3

0

while-true-waitループはどうですか?

#!/bin/bash
SERVER_PID=""
SERVER_NAME="npm start"

start_server() {
    $SERVER_NAME &
    SERVER_PID=$!
    SERVER_ACTIVE=true
}
terminate_server() {
    [ ! "xSERVER_PID" = "X" ] && kill -SIGTERM $SERVER_PID
    SERVER_PID=""
}
refresh_server() {
    terminate_server
    start_server
}

trap refresh_server SIGHUP
start_server
while $SERVER_ACTIVE; do
  SERVER_ACTIVE=false
  wait $SERVER_PID
done

スクリプト内で明示的に、またはbashに隠されている場所で繰り返す必要がある場合は、ある種の待機イベントループが必要です。

于 2013-02-21T21:47:48.867 に答える
0

bash でのシグナルトラップ

例外からの復帰

他のプログラミング言語でシグナリングを使用する場合と同様に、シグナル トラップは間違った方法で簡単に実行できます。

使用する場合、トラップ評価で関数を処理するtrap必要はありませんが、例外の実行をできるだけ短くするために、トラップ例外の終了後にメインプログラムがチェックできるフラグのみを設定する必要があります。

特に、トラップ実行レベルでサブプロセスを開始する必要はありません!fork

正しい例

#!/bin/bash

SERVER_PID=""
CMD_TRAP=""

npm() { #Doing something that could be checked from external
    if [ "$1" ] && [ "$1" == "start" ] ;then
    while :;do
        date "+%s%N" >/tmp/dummyfile.txt
        sleep .333
          done
    fi
}

start_server() {
    npm start &
    SERVER_PID=$!
}
terminate_server() {
    [ "$SERVER_PID" ] && ps $SERVER_PID &>/dev/null && kill -TERM $SERVER_PID
    SERVER_PID=""
}
refresh_server() {
    terminate_server
    start_server
}

printf "for:\n   server restart, hit: 'kill -USR2 %d'\n" $$
printf "   server stop, hit: 'kill %d' (or Ctrl+C)\n" $$

trap 'CMD_TRAP=refresh' USR2 HUP
trap 'CMD_TRAP=terminate' TERM INT

start_server
while [ "$SERVER_PID" ];do 
    wait $SERVER_PID
    case "$CMD_TRAP" in
        refresh   ) refresh_server   ;;
        terminate ) terminate_server ;;
        *         ) refresh_server   ;;        # in case server just end.
      esac;
    CMD_TRAP=""
    [ "$SERVER_PID" ] && echo "LOOP." || echo "EXIT."
  done

特徴

このデモ スクリプトは次のことを行います。

  • スクリプトの開始時にサービスが開始されます。
  • USR2またはHUP信号が受信されると、サービスが再開されます。
  • サービスが終了するか、信号を受信した場合にサービスが再開され、
  • TERM信号が受信されるか 、サービスが適切に停止されます
    • Ctrl-Cコンソールでヒットした場合。
  • 例外は正しく処理されます (すぐにメインルーチンに戻ります)
  • 不要な/管理されていないエラー メッセージがない

出力サンプル

ウィンドウ1

tty
/dev/pts/0

ウィンドウ2

ps --tty pts/0 fw
  PID TTY      STAT   TIME COMMAND
 2996 pts/0    Ss     0:01 bash
 5187 pts/0    S+     0:00  \_ bash

ウィンドウ1

./serverScript.sh 
for:
   server restart, hit: 'kill -USR2 11469'
   server stop, hit: 'kill 11469' (or Ctrl+C)

ウィンドウ2

ps --tty pts/0 fw
  PID TTY      STAT   TIME COMMAND
 2996 pts/0    Ss     0:01 bash
 5187 pts/0    S      0:00  \_ bash
11469 pts/0    S+     0:00      \_ /bin/bash ./servermon.sh
11470 pts/0    S+     0:00          \_ /bin/bash ./servermon.sh

cat /tmp/dummyfile.txt 
1361603642256133674

cat /tmp/dummyfile.txt 
1361603648712606114

    ps --tty pts/0 fw
  PID TTY      STAT   TIME COMMAND
 2996 pts/0    Ss     0:01 bash
 5187 pts/0    S      0:00  \_ bash
11469 pts/0    S+     0:00      \_ /bin/bash ./servermon.sh
11470 pts/0    S+     0:01          \_ /bin/bash ./servermon.sh
16814 pts/0    S+     0:00              \_ sleep .333

kill -USR2 11469

ウィンドウ1

LOOP.

ウィンドウ2

    ps --tty pts/0 fw
  PID TTY      STAT   TIME COMMAND
 2996 pts/0    Ss     0:01 bash
 5187 pts/0    S      0:00  \_ bash
11469 pts/0    S+     0:00      \_ /bin/bash ./servermon.sh
17152 pts/0    S+     0:00          \_ /bin/bash ./servermon.sh
17532 pts/0    S+     0:00              \_ sleep .333

cat /tmp/dummyfile.txt
1361604208069564188
cat /tmp/dummyfile.txt
1361604209103660589

kill -USR2 11469

ウィンドウ1

LOOP.

ウィンドウ2

cat /tmp/dummyfile.txt
1361604278583723517

cat /tmp/dummyfile.txt
1361604279605292149

kill 11469

ウィンドウ1

EXIT.
$

ウィンドウ 1 は、ループサーバー サブプロセスを終了します。

ウィンドウ1

./serverScript.sh 
for:
   server restart, hit: 'kill -USR2 19232'
   server stop, hit: 'kill 19232' (or Ctrl+C)

次にCtrl+Cが押された場合:

ウィンドウ1

^CEXIT.
$

ウィンドウ2

ps --tty pts/0 fw
  PID TTY      STAT   TIME COMMAND
 2996 pts/0    Ss     0:01 bash
 5187 pts/0    S+     0:00  \_ bash

説明

例外をスタックできませんでした。したがって、例外が実行されている間、別の割り込みを無視できます。

refresh_server()これは、サーバーを再起動する前に、関数がいくつかのログを圧縮してローテーションする必要があるサンプルの場合に重要になる可能性があります。

refresh_server() {
    terminate_server
    lockedfilename=-$(date +%F_%H-%M-%S-$$)
    mv /srv/logfile /srv/logfile-$lockedfilename
    gzip /srv/logfile-$lockedfilename
    start_server
}

多くの割り込みは、メイン ループで要約または無視できますが、処理はメイン レベルでのみ実行する必要があります。

何が悪いのかについての小さなデモがあります:

ウィンドウ1

trap "echo USR2 sleep 4;sleep 4" USR2
while :;do printf "\r%s " $(date +%s%N);sleep .333;done
1361606565xxxxxxxxx

(xxxxxxxxx変化 3x / 秒)

ウィンドウ2

for ((i=5;i--;));do echo KILL;kill -USR2 5187;sleep .5;done
KILL
KILL
KILL
KILL
KILL

1361606722582175969 USR2 sleep 4
USR2 sleep 4
1361606770xxxxxxxxx

ループ全体でトラップされたのは、5 回中 2 回の割り込みだけでした。

説明を検索すると: 5 x 0.5 = 2.5 秒。スリープ時間は 4 秒よりはるかに短いのに、5 回すべてではなく 2 回目の割り込みを受け取ったのはなぜですか??

メインループでアントラップ

メインループでトラップを解除するためのちょっとしたトリックがあります:

while [ "$SERVER_PID" ];do 
    wait $SERVER_PID

    OLDIFS="$IFS" IFS=$'\n'
    TRAPS=($(trap))                            # save traps
    IFS="$OLDIFS"
    eval "$(printf "trap -- %s\n" ${TRAPS[@]##*\'})"  # untrap

    case "$CMD_TRAP" in
        refresh   ) refresh_server   ;;
        terminate ) terminate_server ;;
        *         ) refresh_server   ;;        # in case server just end.
      esac;
    CMD_TRAP=""
    if [ "$SERVER_PID" ]
    then echo "LOOP."
    else echo "EXIT."

        eval "$(printf "%s\n" "${TRAPS[@]}")"      # restore traps
    fi
  done
于 2013-02-23T00:47:05.510 に答える
0

これは、末尾再帰の start_server を使用したソリューションで、コードにわずかな変更を加えるだけです。(1 行を削除し、 を含む 3 行を追加HUPPED)

HUPPED=false
SERVER_PID=""

start_server() {
    npm start &
    SERVER_PID=$!
    wait $SERVER_PID
    if $HUPPED; then HUPPED=false; start_server; fi
}
terminate_server() {
    [ ! "xSERVER_PID" = "X" ] && kill -SIGTERM $SERVER_PID
    SERVER_PID=""
}
refresh_server() {
    HUPPED=true
    terminate_server
    #start_server
}

trap refresh_server SIGHUP
start_server
于 2013-02-23T01:16:47.283 に答える