gen_server のコールバックモジュール内で badarith が発生すると supervisor ごと落とされる
検証コード
-module(test_sup). -author('cooldaemon@gmail.com'). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). init(_Args) -> Flags = {one_for_one, 1, 1}, Children = [ { test_gen, {test_gen, start_link, [[]]}, permanent, brutal_kill, worker, [test_gen] } ], {ok, {Flags, Children}}.
-module(test_gen). -author('cooldaemon@gmail.com'). %-behaviour(gen_server). -export([start_link/1]). -export([add/2, exit/0]). -export([ init/1, handle_call/3, handle_cast/2, %handle_info/2, terminate/2, code_change/3 ]). start_link(Args) -> gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []). add(A, B) -> gen_server:call(?MODULE, {add, A, B}). exit() -> gen_server:cast(?MODULE, exit). init(_Args) -> {ok, []}. handle_call({add, A, B}, _From, State) -> {reply, A + B, State}; handle_call(Request, _From, State) -> {stop, {unknown_call, Request}, State}. handle_cast(exit, State) -> exit(normal), {noreply, State}; handle_cast(_Message, State) -> {noreply, State}. %handle_info(_Info, State) -> % {noreply, State}. terminate(Reason, _State) -> io:fwrite("Called terminate:[~p]~n", [Reason]), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}.
% erl 1> test_sup:start_link(). {ok,<0.33.0>} 2> whereis(test_gen). <0.34.0> 3> test_gen:add(1, 1). 2 4> test_gen:exit(). called terminate:[normal] ok 5> whereis(test_gen). <0.38.0> 6> test_gen ! bad_message. called terminate:[{undef,[{test_gen,handle_info,[bad_message,[]]}, {gen_server,handle_msg,5}, {proc_lib,init_p,5}]}] bad_message =ERROR REPORT==== 18-Feb-2009::12:13:53 === ** Generic server test_gen terminating ** Last message in was bad_message ** When Server state == [] ** Reason for termination == ** {'function not exported', [{test_gen,handle_info,[bad_message,[]]}, {gen_server,handle_msg,5}, {proc_lib,init_p,5}]} 7> whereis(test_gen). <0.42.0> 8> test_gen:add(dog, cat). called terminate:[{badarith,[{test_gen,handle_call,3},{proc_lib,init_p,5}]}] =ERROR REPORT==== 18-Feb-2009::12:15:47 === ** Generic server test_gen terminating ** Last message in was {add,dog,cat} ** When Server state == [] ** Reason for termination == ** {badarith,[{test_gen,handle_call,3},{proc_lib,init_p,5}]} =ERROR REPORT==== 18-Feb-2009::12:15:47 === ** Generic server test_sup terminating ** Last message in was {'EXIT',<0.31.0>, {{{badarith, [{test_gen,handle_call,3}, {proc_lib,init_p,5}]}, {gen_server,call,[test_gen,{add,dog,cat}]}}, [{gen_server,call,2}, {erl_eval,do_apply,5}, {shell,exprs,6}, {shell,eval_exprs,6}, {shell,eval_loop,3}]}} ** When Server state == {state, {local,test_sup}, one_for_one, [{child,<0.44.0>,test_gen, {test_gen,start_link,[[]]}, permanent,brutal_kill,worker, [test_gen]}], {dict,0,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[], []}, {{[],[],[],[],[],[],[],[],[],[],[],[],[],[], [],[]}}}, 60,1, [{1234,926947,315968}], test_sup,[]} ** Reason for termination == ** {{{badarith,[{test_gen,handle_call,3},{proc_lib,init_p,5}]}, {gen_server,call,[test_gen,{add,dog,cat}]}}, [{gen_server,call,2}, {erl_eval,do_apply,5}, {shell,exprs,6}, {shell,eval_exprs,6}, {shell,eval_loop,3}]} ** exception exit: {{badarith,[{test_gen,handle_call,3},{proc_lib,init_p,5}]}, {gen_server,call,[test_gen,{add,dog,cat}]}} in function gen_server:call/2 9> whereis(test_gen). undefined
回避方法
途方に暮れて Google 先生に泣きついたら、下記の ML ログを発見できた。
http://erlang.org/pipermail/erlang-questions/2007-March/025397.html
理由を見て納得したけど、回避方法が catch って・・・。今後の設計方針を見直す必要があるなぁ。