誰が見張りを見ているのですか?-(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.