プロセスをちゃんと終了させるのは Erlang のプログラミングでとても重要です。
gen_server を終了するにはいくつかの方法があります。
gen_server の callback
init/1
{stop, Reason} を使用します。
handle_call/3
{stop, Reason, Reply, NewState} という値を戻してから終了します。
handle_cast/2
{stop, Reason, NewState} を使用します。これは call でも使えます。
cast は非同期なので戻り値は常に ok のため、 Reply は使用できません。
handle_info/2
これは call と同様 {stop, Reason, State} を使用します。
stop
18.0 で gen_server:stop/1,3 が導入されました。これは外から gen_server プロセスを終了させられます。
stop/1 では terminate/2 に上がってくる理由はデフォルトでは normal です。
もし変えたい場合は stop/3 を使います。
shutdown
終了の Reason には 3 つ report を上げない方法があります。その 3 つの理由以外では error_logger:format/2 が上がります。
- normal
- shutdown
- {shutdown, Reason}
上記の gen_server の callback を使うときに 正常終了 をする場合は、この 3 を使います。
正常終了というのはレポートを上げない終了です。
たとえば init/1 時に問題が合った場合はその理由を元に {stop, Reason} とやりがちですが、これだとレポートが上がりエラーとなります。
エラーレポートを上げないで終了する場合は {stop, {shutdown, Reason}} としましょう。
もし gen_server を simple_one_for_one の supervisor:start_child/2 で上げていた場合の {error, Reason} のReason は {shutdown, Reason} となります。
丁寧に終了するメリット
不必要にログをはかなくなります。握りつぶしているわけではなくちゃんと Reason を指定すれば terminate で拾えますのでそこでログをはいた方が良いです。
simple_one_for_one などでプロセスを管理している場合は monitor で連携したりすることもあるでしょう。その際正常に終了しないと、プロセスがクラッシュしたと判断されてしまうことがあります。
まとめ
Erlang ではプロセスが簡単に上げられます。立ち上げるのは簡単ですが、役目を終えたプロセスを正常に終了することを意識した記事はあまりないので書き出してみました。
参考
リンクに関する話は以下を読みましょう。
Top comments (0)