【问题标题】:Starting a child with simple_one_for_one supervisor用 simple_one_for_one 主管开始一个孩子
【发布时间】:2016-06-11 06:01:15
【问题描述】:

您如何开始使用simple_one_for_one 主管的孩子? 我正在阅读 LYSE 书,目前在 Dynamic Supervision 部分:http://learnyousomeerlang.com/supervisors#dynamic-supervision

作者启动child如下,但是我不知道djembe是在哪里定义的:

1> supervisor:start_child(band_supervisor, [djembe, good]).
Musician Janet Tennelli, playing the djembe entered the room
{ok,<0.690.0>}
2> supervisor:start_child(band_supervisor, [djembe, good]).
{error,{already_started,<0.690.0>}}

这是我的尝试:

2> supervisor:start_link(band_supervisor, jamband).
{ok,<0.40.0>}
3> supervisor:start_child(band_supervisor, [djembe, good]).

=ERROR REPORT==== 28-Feb-2016::03:52:56 ===
** Generic server <0.40.0> terminating
** Last message in was {'EXIT',<0.33.0>,
                           {{noproc,
                                {gen_server,call,
                                    [band_supervisor,
                                     {start_child,[djembe,good]},
                                     infinity]}},
                            [{gen_server,call,3,
                                 [{file,"gen_server.erl"},{line,212}]},
                             {erl_eval,do_apply,6,
                                 [{file,"erl_eval.erl"},{line,673}]},
                             {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
                             {shell,eval_exprs,7,
                                 [{file,"shell.erl"},{line,641}]},
                             {shell,eval_loop,3,
                                 [{file,"shell.erl"},{line,626}]}]}}
** When Server state == {state,
                            {<0.40.0>,band_supervisor},
                            simple_one_for_one,
                            [{child,undefined,jam_musician,
                                 {musicians,start_link,[]},
                                 temporary,1000,worker,
                                 [musicians]}],
                            undefined,3,60,[],band_supervisor,jamband}
** Reason for termination ==
** {{noproc,{gen_server,call,
                        [band_supervisor,
                         {start_child,[djembe,good]},
                         infinity]}},
    [{gen_server,call,3,[{file,"gen_server.erl"},{line,212}]},
     {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,673}]},
     {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
     {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
     {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}
** exception exit: {noproc,{gen_server,call,
                                       [band_supervisor,
                                        {start_child,[djembe,good]},
                                        infinity]}}
     in function  gen_server:call/3 (gen_server.erl, line 212)

这是主管的样子:

-module(band_supervisor).
-behaviour(supervisor).

-export([start_link/1]).
-export([init/1]).

start_link(Type) ->
    supervisor:start_link({local,?MODULE}, ?MODULE, Type).

%% The band supervisor will allow its band members to make a few
%% mistakes before shutting down all operations, based on what
%% mood he's in. A lenient supervisor will tolerate more mistakes
%% than an angry supervisor, who'll tolerate more than a
%% complete jerk supervisor
init(lenient) ->
    init({one_for_one, 3, 60});
init(angry) ->
    init({rest_for_one, 2, 60});
init(jerk) ->
    init({one_for_all, 1, 60});
init(jamband) ->
    {ok, {{simple_one_for_one, 3, 60},
         [{jam_musician,
           {musicians, start_link, []},
           temporary, 1000, worker, [musicians]}
         ]}};
init({RestartStrategy, MaxRestart, MaxTime}) ->
    {ok, {{RestartStrategy, MaxRestart, MaxTime},
         [{singer,
           {musicians, start_link, [singer, good]},
           permanent, 1000, worker, [musicians]},
          {bass,
           {musicians, start_link, [bass, good]},
           temporary, 1000, worker, [musicians]},
          {drum,
           {musicians, start_link, [drum, bad]},
           transient, 1000, worker, [musicians]},
          {keytar,
           {musicians, start_link, [keytar, good]},
           transient, 1000, worker, [musicians]}
         ]}}.

以下是音乐家:

-module(musicians).
-behaviour(gen_server).

-export([start_link/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2,
         handle_info/2, code_change/3, terminate/2]).

-record(state, {name="", role, skill=good}).
-define(DELAY, 750).

start_link(Role, Skill) ->
    gen_server:start_link({local, Role}, ?MODULE, [Role, Skill], []).

stop(Role) -> gen_server:call(Role, stop).

init([Role, Skill]) ->
    %% To know when the parent shuts down
    process_flag(trap_exit, true),
    %% sets a seed for random number generation for the life of the process
    %% uses the current time to do it. Unique value guaranteed by now()
    random:seed(now()),
    TimeToPlay = random:uniform(3000),
    Name = pick_name(),
    StrRole = atom_to_list(Role),
    io:format("Musician ~s, playing the ~s entered the room~n",
              [Name, StrRole]),
    {ok, #state{name=Name, role=StrRole, skill=Skill}, TimeToPlay}.

handle_call(stop, _From, S=#state{}) ->
    {stop, normal, ok, S};
handle_call(_Message, _From, S) ->
    {noreply, S, ?DELAY}.

handle_cast(_Message, S) ->
    {noreply, S, ?DELAY}.

handle_info(timeout, S = #state{name=N, skill=good}) ->
    io:format("~s produced sound!~n",[N]),
    {noreply, S, ?DELAY};
handle_info(timeout, S = #state{name=N, skill=bad}) ->
    case random:uniform(5) of
        1 ->
            io:format("~s played a false note. Uh oh~n",[N]),
            {stop, bad_note, S};
        _ ->
            io:format("~s produced sound!~n",[N]),
            {noreply, S, ?DELAY}
    end;
handle_info(_Message, S) ->
    {noreply, S, ?DELAY}.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

terminate(normal, S) ->
    io:format("~s left the room (~s)~n",[S#state.name, S#state.role]);
terminate(bad_note, S) ->
    io:format("~s sucks! kicked that member out of the band! (~s)~n",
              [S#state.name, S#state.role]);
terminate(shutdown, S) ->
    io:format("The manager is mad and fired the whole band! "
              "~s just got back to playing in the subway~n",
              [S#state.name]);
terminate(_Reason, S) ->
    io:format("~s has been kicked out (~s)~n", [S#state.name, S#state.role]).

%% Yes, the names are based off the magic school bus characters
%% 10 names!
pick_name() ->
    %% the seed must be set for the random functions. Use within the
    %% process that started with init/1
    lists:nth(random:uniform(10), firstnames())
    ++ " " ++
    lists:nth(random:uniform(10), lastnames()).

firstnames() ->
    ["Valerie", "Arnold", "Carlos", "Dorothy", "Keesha",
     "Phoebe", "Ralphie", "Tim", "Wanda", "Janet"].

lastnames() ->
    ["Frizzle", "Perlstein", "Ramon", "Ann", "Franklin",
     "Terese", "Tennelli", "Jamal", "Li", "Perlstein"].

【问题讨论】:

    标签: erlang erlang-otp


    【解决方案1】:

    learnyousomeerlang.com 是一个很好的信息来源,但有时我觉得它太详细了。我通过阅读supervisor OTP 文档直接了解了 OTP 的这一部分。如果您只想了解动态儿童,您可能不需要gen_server。见my simple implementation:

    -module(estp_proj_sup).
    -behaviour(supervisor).
    
    %% API
    -export([start_link/0]).
    
    %% Supervisor callbacks
    -export([init/1, add/2]).
    
    -define(SERVER, ?MODULE).
    
    start_link() ->
        supervisor:start_link({local, ?SERVER}, ?MODULE, []).
    
    init([]) ->
        Child = ?WORKER(estp_project),
        {ok, {{simple_one_for_one, 3, 30}, [Child]}}.
    
    add(Name, Cfg) ->
        Server = estp_project:server_name(Name),
        State = [{name, Name}|Cfg],
        case whereis(Server) of
            undefined ->
                add_child(Server, State);
            Pid ->
                delete_child(Server, Pid),
                add_child(Server, State)
        end.
    
    add_child(Server, State) ->
        supervisor:start_child(?SERVER, [Server, State]).
    
    delete_child(Server, Pid) ->
        ok = supervisor:terminate_child(?SERVER, Pid).
    

    动态子名称estp_project:server_name/1 是这样创建的:

    server_name(Name) ->
        Module = atom_to_binary(?MODULE, utf8),
        Binary = atom_to_binary(Name, utf8),
        binary_to_atom(<<Module/binary, <<"$">>/binary, Binary/binary>>, utf8).
    

    worker被定义为:

    -define(SHUTDOWN_TIMEOUT, 5000).
    -define(WORKER(I), {I, {I, start_link, []}, permanent, ?SHUTDOWN_TIMEOUT, worker, [I]}).
    

    然后,您只需调用 estp_proj_sup:add(Name, Cfg) 即可添加孩子,就像在 this code 中一样:

    process(Res) ->
        %% Res contains parsed list of project names and their configurations
        [set_project(Name, Cfg) || {Name, {ok, Cfg}} <- Res].
    
    set_project(Name, Cfg) ->
        case estp_proj_sup:add(Name, Cfg) of
            {ok, _Pid} -> ok;
            {error, _} = Err -> Err
        end.
    

    无论如何,我尝试了您的示例,它似乎正在工作:

    4> {ok, S} = band_supervisor:start_link(jamband).
    {ok,<0.47.0>}
    5> supervisor:start_child(band_supervisor, [djembe, good]).
    Musician Wanda Terese, playing the djembe entered the room
    {ok,<0.49.0>}
    Wanda Terese produced sound!
    Wanda Terese produced sound!
    Wanda Terese produced sound!
    Wanda Terese produced sound!
    Wanda Terese produced sound!
    6> supervisor:start_child(band_supervisor, [djembe, good]).
    {error,{already_started,<0.49.0>}}
    Wanda Terese produced sound!
    Wanda Terese produced sound!
    

    【讨论】:

    • 奇怪,现在可以了。一定是犯了什么愚蠢的错误。无论如何,谢谢。
    猜你喜欢
    • 2017-05-02
    • 2014-12-09
    • 2017-02-21
    • 2012-11-04
    • 2012-05-07
    • 1970-01-01
    • 2013-06-19
    • 2014-06-17
    • 1970-01-01
    相关资源
    最近更新 更多