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 って・・・。今後の設計方針を見直す必要があるなぁ。