当接收关闭信号时,动态启动子将导致异常

时间:2015-07-03 07:57:02

标签: erlang otp supervisor

主管:

-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]}]

收到{0}时的例外:

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: pid,不应该存在。

文件中有两处解释了这一点,但它们之间存在冲突。

  1. 如果孩子不是undefined即使它返回temporary,孩子的规范将由主管保管。
  2.   

    start定义用于启动子进程的函数调用。它必须是用作apply(M,F,A)的模块函数参数元组{M,F,A}。

         

    start函数必须创建并链接到子进程,并且必须返回{ok,Child}或{ok,Child,Info},其中Child是子进程的pid,Info是任意一个被忽略的术语。主管。

         

    如果由于某种原因导致子进程无法启动,则start函数也可以返回ignore,在这种情况下,子进程将由主管保存(除非它是临时子进程),但是不存在的子进程将是忽略。

      如果在开始时返回ignore
    1. simple_one_for_one pid将不会添加到主管。
    2.   

      如果子进程启动函数返回ignore,则将子规范添加到超级用户(除非超级用户是一个simple_one_for_one超级用户,见下文),pid设置为undefined,函数返回{ok,undefined}。 / p>      

      对于simple_one_for_one管理程序,当子进程启动函数返回忽略时,函数返回{ok,undefined}并且没有子进程添加到主管。

      我对文件感到困惑。我选择ignore重新启动策略,因为子应该在崩溃时重新启动。但是我怎么能在这里避免这个例外呢?

1 个答案:

答案 0 :(得分:0)

好的,我再次阅读你的问题。文档说明如果你在孩子的启动功能中返回忽略,则该孩子启动。对于simple_one_for_one监督者,也不会保留子规范(这是合乎逻辑的,因为在监督者的开始只保存了一个规范)。这意味着该行:

{undefined,undefined,worker,[mod_guild_chapter]},

只是说没有启动子进程。因此,该过程不能成为您例外的原因。崩溃报告为您提供崩溃过程的pid,其为&lt; 0.9475.0&gt;。您可以在which_children的返回列表中找到它。这是检查发现崩溃原因的过程。