Hatena::ブログ(Diary)

cooldaemonの備忘録 RSSフィード

2011-09-26

続:gen_server のコールバックモジュール内で badarith が発生すると supervisor ごと落とされる

二年半前に gen_server のコールバックモジュール内で badarith が発生すると supervisor ごと落とされる というメモを残したにも関わらず、すっかり内容を忘れてしまい、変な Process Design の poolboy*1 の poolboy_sup が安全か検証をするのに時間が掛かったのでメモを残す。

もともと、Erlang ML で下記のようなやり取りがあった。

erlang-questions: Supervisor does not restart Gen Server

ざっくり要約すると Erlang Shell が停止してしまい、道連れで Supervisor が停止している。回避策は try catch …という内容。

これをすっかり忘れており「badarith 例外発生 = 全 Supervisor 停止」と勘違いして覚えていたのが、そもそもの勘違いの発端。

実際は、badarith が発生すると、"何故か" Erlang Shell が停止してしまい、Erlang Shell と link 関係にある Supervisor が "何故か" 停止している…が正しい。

下記に試した内容を列挙する。

badarith を発生させるプロセスの起動方法結果
Erlang Shell -> Supervisor -> Worker(gen_server)Supervisor が Worker を再起動した後、erlang:apply/2 が停止し、link 先の Supervisor が道連れに停止
Erlang Shell -> Application -> Supervisor -> Worker(gen_server)Worker 再起動
Erlang Shell (spawn) -> システムプロセス(trap_exit = true) -> worker(gen_server)システムプロセスが Worker 停止のメッセージ受信
Erlang Shell (spawn_link) -> システムプロセス(trap_exit = true) -> worker(gen_server)システムプロセスが Worker 停止と erlang:apply/2 停止のメッセージ受信

Supervisor には、start は無く start_link しかない。Erlang Shell 上から start_link を実行すると、起動した Supervisor は Erlang Shell と link 関係になってしまう。この辺りが、関係しているようにも思えるが…下記の疑問が残る。

  • worker(gen_server) と直接 link 関係には無い Erlang Shell が、何故、worker(gen_server) の badarith を補足しているのか?
  • Supervisor ではないシステムプロセスは、Erlang Shell の EXIT メッセージを補足するのに、Supervisor の EXIT を補足する handle_info/2 は、何故、評価されていないのか?(print debug で確認済み)

疑問は残るが、とりあえず Erlang Shell が停止しなければ、Worker で badarith が発生しても平気であるため、下記の回避策が考えられる(おすすめ順)。

  • Application 化する(一番、おすすめ)
  • ML 推奨の try catch(throw や exit を補足するならともかく、error を補足するのは、ちょっと…)
  • Erlang Shell 上で catch_exception(true). を評価しておく(これの副作用は、現在、調査中)

既に Erlang 歴 3 年目なのに、こんな所で躓いているから、いつまでも Erlang 界隈の底辺なんだろうなぁ…

*1:後日、poolboy の紹介を書く予定

tkurotkuro 2011/09/27 17:44 >worker(gen_server) と直接 link 関係には無い Erlang Shell が、何故、worker(gen_server) の badarith を補足しているのか?
実はgen_server:callが諸悪の根源だったりとか。。。

call(Name, Request) ->
case catch gen:call(Name, '$gen_call', Request) of
{ok,Res} ->
Res;
{'EXIT',Reason} ->
exit({Reason, {?MODULE, call, [Name, Request]}})  << コイツ
end.

cooldaemoncooldaemon 2011/10/01 22:28 あーー!なるほど。
gen_server は、全く眼中にありませんでした。
後で、gen_server2 とか作って動作確認してみます。

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/cooldaemon/20110926/1317030222
Connection: close