2

誰が見張りを見ているのですか?-(Decimus Iunius Iuvenalis)

私は次の設定をしています:

1つのノード('one@erlang.enzo')で、別のノード('two@erlang.enzo')を実行しているウォッチドッグを持つサーバープロセスが実行されています。サーバーが起動すると、リモートノードでウォッチドッグが起動します。サーバーが正常に終了しない場合、ウォッチドッグはサーバーを再起動します。ウォッチドッグが終了すると、サーバーはウォッチドッグを再開します。

ネットワークが起動した後、サーバーはランレベルの一部として起動されます。

サーバーはリモートノードも監視し、リモートノード(つまりノード)がオンラインになるとすぐにウォッチドッグを開始します。サーバーとウォッチドッグ間の接続が失われる理由は2つあります。1つは、ネットワークがダウンする可能性があることです。次に、ノードがクラッシュまたは強制終了される可能性があります。

私のコード機能しているようですが、次のことが起こっているのではないかと少し疑っています。

  • ウォッチドッグノードがシャットダウン(または強制終了またはクラッシュ)されて再起動されると、サーバーはウォッチドッグを正しく再起動します。
  • ただし、ネットワークに障害が発生し、ウォッチドッグノードが実行を続けると、接続が再確立されたときにサーバーが新しいウォッチドッグを開始し、1つのゾンビウォッチドッグを残します。

私の質問は

  • (A)ゾンビを作成しますか?
  • (B)ネットワークが失われた場合、サーバーはウォッチドッグがまだ生きているかどうか(およびその逆)をどのように確認できますか?
  • (C)Bが可能な場合、古いサーバーと古いウォッチドッグを再接続するにはどうすればよいですか?
  • (D)著名な読者であるあなたは、私のセットアップで他にどのような大きな(そして小さな)欠陥を見つけましたか?

編集:die andkill_dogメッセージは、不正な出口を偽造するためのものであり、デバッグを超えることはありません。

コードは次のとおりです。


-module (watchdog).
-compile (export_all).

init () ->
    io:format ("Watchdog: Starting @ ~p.~n", [node () ] ),
    process_flag (trap_exit, true),
    loop ().

loop () ->
    receive
        die -> 1 / 0;
        {'EXIT', _, normal} ->
            io:format ("Watchdog: Server shut down.~n");
        {'EXIT', _, _} ->
            io:format ("Watchdog: Restarting server.~n"),
            spawn ('one@erlang.enzo', server, start, [] );
        _ -> loop ()
    end.

-module (server).
-compile (export_all).

start () ->
    io:format ("Server: Starting up.~n"),
    register (server, spawn (fun init/0) ).

stop () ->
    whereis (server) ! stop.

init () ->
    process_flag (trap_exit, true),
    monitor_node ('two@erlang.enzo', true),
    loop (down, none).

loop (Status, Watchdog) ->
    {NewStatus, NewWatchdog} = receive
        die -> 1 / 0;
        stop -> {stop, none};
        kill_dog ->
            Watchdog ! die,
            {Status, Watchdog};
        {nodedown, 'two@erlang.enzo'} ->
            io:format ("Server: Watchdog node has gone down.~n"),
            {down, Watchdog};
        {'EXIT', Watchdog, noconnection} ->
            {Status, Watchdog};
        {'EXIT', Watchdog, Reason} ->
            io:format ("Server: Watchdog has died of ~p.~n", [Reason] ),
            {Status, spawn_link ('two@erlang.enzo', watchdog, init, [] ) };
        _ -> {Status, Watchdog}
    after 2000 ->
        case Status of
            down -> checkNode ();
            up -> {up, Watchdog}
        end
    end,
    case NewStatus of
        stop -> ok;
        _ -> loop (NewStatus, NewWatchdog)
    end.

checkNode () ->
    net_adm:world (),
    case lists:any (fun (Node) -> Node =:= 'two@erlang.enzo' end, nodes () ) of
        false ->
            io:format ("Server: Watchdog node is still down.~n"),
            {down, none};
        true ->
            io:format ("Server: Watchdog node has come online.~n"),
            monitor_node ('two@erlang.enzo', true),
            Watchdog = spawn_link ('two@erlang.enzo', watchdog, init, [] ),
            {up, Watchdog}
    end.
4

1 に答える 1

1

モジュールを使用globalしてウォッチドッグを登録すると、懸念を防ぐことができます。

watchdog.erl:

-module (watchdog).
-compile (export_all).

init () ->
    io:format ("Watchdog: Starting @ ~p.~n", [node () ] ),
    process_flag (trap_exit, true),
    global:register_name (watchdog, self ()),
    loop ().

loop () ->
    receive
        die -> 1 / 0;
        {'EXIT', _, normal} ->
            io:format ("Watchdog: Server shut down.~n");
        {'EXIT', _, _} ->
            io:format ("Watchdog: Restarting server.~n"),
            spawn ('one@erlang.enzo', server, start, [] );
        _ -> loop ()
    end.

server.erl:

checkNode () ->
    net_adm:world (),
    case lists:any (fun (Node) -> Node =:= 'two@erlang.enzo' end, nodes () ) of
        false ->
            io:format ("Server: Watchdog node is still down.~n"),
            {down, none};
        true ->
            io:format ("Server: Watchdog node has come online.~n"),
            global:sync (), %% not sure if this is necessary
            case global:whereis_name (watchdog) of
                undefined -> 
                    io:format ("Watchdog process is dead"),
                    Watchdog = spawn_link ('two@erlang.enzo', watchdog, init, [] );
                Watchdog ->
                    io:format ("Watchdog process is still alive")
            end,
            {up, Watchdog}
    end.
于 2011-08-08T06:22:01.520 に答える