2

主管:

-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。

文档中有两个地方对此进行了解释,但它们之间存在冲突。

  1. temporary如果孩子不是,即使它返回,子规范将由主管保留ignore

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

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

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

  1. simple_one_for_one如果启动时返回,pid 将不会添加到主管ignore

如果子进程启动函数返回忽略,则将子规范添加到主管(除非主管是 simple_one_for_one 主管,请参见下文),将 pid 设置为 undefined 并且函数返回 {ok,undefined}。

在 simple_one_for_one 监督者的情况下,当子进程启动函数返回忽略函数返回 {ok,undefined} 并且没有子进程添加到监督者。

我被文件弄糊涂了。我选择transient重启策略是因为孩子在崩溃时应该重启。但是我怎样才能在这里避免这个异常呢?

4

1 回答 1

0

好的,我再次阅读了您的问题。文档说,如果您在子项的启动函数中返回忽略,则该子项不会启动。对于 simple_one_for_one 主管,也不会保留子规范(这是合乎逻辑的,因为在主管开始时只保存了一个规范)。这意味着该行:

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

只是说没有子进程已经启动。因此,该过程不能成为您异常的原因。崩溃报告为您提供了崩溃进程的 pid <0.9475.0>。您可以在 which_children 的返回列表中找到它。这是检查以找出崩溃原因的过程。

于 2015-07-06T08:29:16.517 回答