Erlang の監視ツリーで gen_server を停止する
Erlang -- gen_server Behaviour にある監視ツリーに含まれている gen_server の停止を試してみたいと思います。
スーパーバイザーとそれによって監視されるワーカーのサンプルコードは、前回の記事( Erlang の supervisor ビヘイビアを学ぶ - 無題の備忘録 )の sample_sup (supervisor
) モジュールと value_server ( gen_server
) モジュールを使います。
ワーカーのサンプルコードとして value_server を使いますが、下記のように2点変更します。
- まず、
init
関数にprocess_flag(trap_exit, true),
を追加します。これは、スーパーバイザーからの停止命令(shutdown
メッセージ) を補足できるようにするためです。 - 次に、
terminate/2
関数を追加します。この関数にクリーンアップ処理を実装します。この例では、io:format
で単に文字列をErlangシェルに表示します。
上記の2点を変更すると、value_server モジュールは下記のようなサンプルコードになります。
-module(value_server). -behaviour(gen_server). -export([start_link/1, value/1, pid/1]). -export([init/1, handle_call/3, handle_cast/2, terminate/2]). start_link({Name, Value}) -> gen_server:start_link({local, Name}, ?MODULE, Value, []). value(Name) -> gen_server:call(Name, value). pid(Name) -> gen_server:call(Name, pid). init(Value) -> process_flag(trap_exit, true), {ok, Value}. handle_call(value, _From, Value) -> {reply, Value, Value}; handle_call(pid, _From, Value) -> {reply, self(), Value}. handle_cast(_Request, Value) -> {noreply, Value}. terminate(Reason, Value) -> io:format("~p terminate reason:~p with value:~p.~n", [self(), Reason, Value]), ok.
下記は使用例です。
> c(sample_sup). {ok,sample_sup} > c(value_server). {ok,value_server} > {ok, Sup} = sample_sup:start_link(). {ok,<0.91.0>} > value_server:value(name_a). value_a > PidA = value_server:pid(name_a). <0.92.0> > is_process_alive(PidA). true > supervisor:terminate_child(Sup, name_a). <0.92.0> terminate reason:shutdown with value:value_a. ok > is_process_alive(PidA). false
sample_sup:start_link()
によってスーパーバイザーを起動します。すると、name_a という名前の子プロセスが起動されます。
value_server:value(name_a)
は、name_a に保持している値を問い合わせるリクエストを送信しています。
value_server:pid(name_a)
によって、ワーカーの Pid を確認しています。
下記の関数によって、name_a の子プロセスを終了しています。すると、value_server の terminate/2
関数に記述した処理が実行されていることがわかります。
> supervisor:terminate_child(Sup, name_a). <0.92.0> terminate reason:shutdown with value:value_a.
最後は、下記の関数で name_a という名前の子プロセスが生きているか調べて、終了されていることを確認しました。
> is_process_alive(PidA). false