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