0

我正在使用取自http://learnyousomeerlang.com/building-applications-with-otp的主管树代码,但我得到一个 noproc 异常,当我尝试让主管启动孩子时我无法弄清楚过程。这是我的shell交互:

   1>  application:start(test).
root supervisor init
ok
    2> test_sup:start_service(service_sup,{service_worker, start_link,[]}).
{ok,<0.39.0>}
   worker supervisor initialise (M: service_worker,F: start_link,A: []) 

    3> test_app:run(service_worker,[]). 
  server run: (name: service_worker args: []) 
    ** exception exit: {noproc,{gen_server,call,[service_worker,{run,[]}]}}
     in function  gen_server:call/2 (gen_server.erl, line 182)

代码是:

-module(test_app).
-behaviour(application).
-export([start/2, stop/1, run/2]).

start(_StartType, _StartArgs) ->
    test_sup:start_link().


run(Name, Args) ->
    service_serv:run(Name, Args).

=====

-module(test_sup).

-behaviour(supervisor).

-export([start_link/0, init/1, stop/0, start_service/2, stop_service/1]). 

-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
    supervisor:start_link({local, service}, ?MODULE, []).

init([]) ->
    io:format("root supervisor init~n"),
    {ok, {{one_for_one, 5, 10},
        []}}.

start_service(Name, MFA) ->
    ChildSpec = {Name,
                 {service_sup, start_link, [Name, MFA]},
                  permanent, 10500, supervisor, [service_sup]},
    io:format("start service supervisor (Name: ~p, MFA: ~p): ", [Name, MFA]),
    supervisor:start_child(service, ChildSpec). 
[snip]

====

-module(service_sup).
-export([start_link/2, init/1]).
-behaviour(supervisor).

start_link(Name, MFA) ->
    supervisor:start_link(?MODULE, {Name, MFA}).

init({Name, MFA}) ->
    MaxRestart = 1,
    MaxTime = 3600,
    {ok, {{one_for_all, MaxRestart, MaxTime},
          [{serv,
             {service_serv, start_link, [Name, self(), MFA]}, 
             permanent,
             5000,
             worker, [service_serv]}]}}.

========

-module(worker_sup).
-export([start_link/1, init/1]).
-behaviour(supervisor).

start_link(MFA) ->
    supervisor:start_link(?MODULE, MFA).

init({M,F,A}) ->
    {ok, {{simple_one_for_one, 5, 3600},
          [{service_worker,
            {M,F,A},
            temporary, 5000, worker, [M]}]}}.

===

-module(service_serv). 

-behaviour(gen_server).

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

-define(WORKER_SUP_SPEC(MFA),
        {worker_sup,
         {worker_sup, start_link, [MFA]},
          permanent,
          10000,
          supervisor,
          [worker_sup]}).        


-record(state, {sup,
                refs,
                queue=queue:new()
                }). 

start(Name, Sup, MFA) when is_atom(Name) ->
    gen_server:start({local, Name}, ?MODULE, {MFA, Sup}, []).                     

start_link(Name, Sup, MFA) when is_atom(Name) ->
    gen_server:start_link({local, Name}, ?MODULE, {MFA, Sup}, []).  

init({MFA, Sup}) ->
    self() ! {start_worker_supervisor, Sup, MFA},
    {ok, #state{}}.

run(Name, Args) ->
    io:format("server run: (name: ~p args: ~p) ~n",[Name, Args]),
    gen_server:call(Name, {run, Args}).

handle_info({start_worker_supervisor, Sup, MFA}, S = #state{}) ->
    {ok, Pid} = supervisor:start_child(Sup, ?WORKER_SUP_SPEC(MFA)),
    {noreply, S#state{sup=Pid}};
handle_info({'DOWN', Ref, process, _Pid, _}, S = #state{refs=Refs}) ->
    case gb_sets:is_element(Ref, Refs) of
        true ->
            handle_down_worker(Ref, S);
        false -> %% Not our responsibility
            {noreply, S}
    end;    
handle_info(Msg, State) ->
    {noreply, State}.

handle_call({run, Args}, _From, S = #state{sup=Sup, refs=R}) ->
    io:format("handle run call ~n"),
    {ok, Pid} = supervisor:start_child(Sup, Args),
    Ref = erlang:monitor(process, Pid),
    {reply, {ok, run, Pid}, S#state{refs=gb_sets:add(Ref,R)}};
[snip]

====

-module(service_worker).
-behaviour(gen_server).
-export([start_link/4, stop/1]).
-export([init/0, init/1, handle_call/3, handle_cast/2,
         handle_info/2, code_change/3, terminate/2]).

start_link(Task, Delay, Max, SendTo) ->
    gen_server:start_link(?MODULE, {Task, Delay, Max, SendTo} , []).

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

init({Task, Delay, Max, SendTo}) ->
    io:format("initialise worker ~n"),
%%  {ok, {Task, Delay, Max, SendTo}}.
    {ok, {Task, Delay, Max, SendTo}, Delay}.

[剪辑]

4

1 回答 1

2

您生成的代码量有点难以解析,但对我来说最突出的是您显然使用原子“service_worker”来引用您启动的进程。

erlang:register(service_worker, Pid)如果您使用该原子注册进程(通过调用或使用 启动进程) ,这一切都很好gen_server:start_link({local, service_worker}, ?MODULE, Args, Opts)。您似乎两者都没有做,并且您收到的错误消息支持该评估。

** exception exit: {noproc,{gen_server,call,[service_worker,{run,[]}]}}
 in function  gen_server:call/2 (gen_server.erl, line 182)

这个错误告诉我们的是gen_server:call无法找到进程(noproc)。的参数gen_server:call包含在错误消息中,在人们期望找到 的地方Pid,我们找到了service_worker

此外,您的service_worker模块似乎是由simple_one_for_one主管启动的。当您需要多个相同“类型”的进程(例如,相同的回调模块)时,可以使用这样的主管。此类主管也不会自行启动工作人员(您必须调用supervisor:start_child(SupPid, ExtraArgs))。

这些是我在您目前的尝试中看到的两个主要问题。为了快速而肮脏的修复,请尝试将{local, service_worker}or{local, ?MODULE}作为第一个参数添加到gen_server:start_linkservice_worker 模块中的调用。请记住,如果您打算启动多个 service_worker 进程,这将不起作用(因为一次只能将一个进程注册到一个原子)。

于 2014-10-02T18:02:14.533 回答