スーパーバイザー:
-module(mod_guild_chapter_sup).
-include("guild_dungeon.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Starts the supervisor
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
%%
%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
%% ignore |
%% {error, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
RestartStrategy = simple_one_for_one,
MaxRestarts = 1000,
MaxSecondsBetweenRestarts = 3600,
SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
Restart = transient,
Shutdown = 60000,
Type = worker,
ModGuildChapter = {'guild_chapter', {'mod_guild_chapter', start_link, []},
Restart, Shutdown, Type, ['mod_guild_chapter']},
{ok, {SupFlags, [ModGuildChapter]}}.
子供:
-module(mod_guild_chapter).
-record(state, {}).
start_link(GuildId, ChapterId) ->
gen_server:start_link(?MODULE, [GuildId, ChapterId], []).
init([GuildId, ChapterId]) ->
case condition() of
true -> ignore;
false -> {ok, #state{})
end.
...omit other callbacks...
supervisor:which_children(mod_guild_chapter_sup)
:
[{undefined,<0.9635.0>,worker,[mod_guild_chapter]},
{undefined,<0.9539.0>,worker,[mod_guild_chapter]},
{undefined,<0.9475.0>,worker,[mod_guild_chapter]},
{undefined,<0.9493.0>,worker,[mod_guild_chapter]},
{undefined,<0.9654.0>,worker,[mod_guild_chapter]},
{undefined,undefined,worker,[mod_guild_chapter]},
{undefined,<0.9658.0>,worker,[mod_guild_chapter]},
{undefined,<0.9517.0>,worker,[mod_guild_chapter]},
{undefined,<0.9567.0>,worker,[mod_guild_chapter]}]
受信時の例外shutdown
:
2015-07-03 14:56:33 =CRASH REPORT====
crasher:
initial call: mod_guild_chapter:init/1
pid: <0.9475.0>
registered_name: []
exception exit: {{function_clause,[{supervisor,'-monitor_dynamic_children/2-fun-1-',[undefined,[100062,10003],{{set,3,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[<0.9658.0>],[],[],[<0.9517.0>],[],[<0.9567.0>],[],[],[]}}},{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}}],[{file,"supervisor.erl"},{line,992}]},{dict,fold_bucket,3,[{file,"dict.erl"},{line,441}]},{dict,fold_seg,4,[{file,"dict.erl"},{line,437}]},{dict,fold_segs,4,[{file,"dict.erl"},{line,433}]},{supervisor,terminate_dynamic_children,3,[{file,"supervisor.erl"},{line,959}]},{gen_server,terminate,6,[{file,"gen_server.erl"},{line,719}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]},[{gen_server,terminate,6,[{file,"gen_server.erl"},{line,744}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}
ancestors: [mod_guild_chapter_sup,mod_guild_sup,yg_sup,<0.82.0>]
messages: []
links: []
dictionary: []
trap_exit: true
status: running
heap_size: 1598
stack_size: 27
reductions: 6586
neighbours:
ご覧のとおり、そこにあってはundefined
ならない pid があります。
ドキュメントにはこれを説明する 2 つの場所がありますが、それらの間に矛盾があります。
temporary
返されても子が存在しない場合、子の指定はスーパーバイザによって保持されますignore
。
start は、子プロセスを開始するために使用される関数呼び出しを定義します。apply(M,F,A) として使用される module-function-arguments タプル {M,F,A} でなければなりません。
start 関数は、子プロセスを作成してリンクする必要があり、{ok,Child} または {ok,Child,Info} を返す必要があります。ここで、Child は子プロセスの pid であり、Info はスーパーバイザーによって無視される任意の用語です。
start 関数は、何らかの理由で子プロセスを開始できない場合にも無視を返すことができます。その場合、子の仕様は (一時的な子でない限り) スーパーバイザーによって保持されますが、存在しない子プロセスは無視されます。
simple_one_for_one
start 時に戻った場合、pid はスーパーバイザに追加されませんignore
。
子プロセス開始関数が無視を返す場合、子仕様がスーパーバイザーに追加され (スーパーバイザーが simple_one_for_one スーパーバイザーでない限り、以下を参照)、pid が未定義に設定され、関数は {ok,undefined} を返します。
simple_one_for_one スーパーバイザーの場合、子プロセス開始関数が ignore を返すと、関数は {ok,undefined} を返し、子はスーパーバイザーに追加されません。
私はその文書に混乱した。transient
クラッシュ時に子が再起動する必要があるため、再起動戦略を選択します。しかし、ここでこの例外を回避するにはどうすればよいですか?