2014-10-02 114 views
0

我正在玩取自主管樹的代碼,但我得到一個noproc例外,我無法弄清楚當我試圖讓一個主管開始子進程。這是我的殼互動:厄蘭管理員開始工人的例外

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

[剪斷]

+0

輸出中的消息('worker supervisor initialise'和'server run')似乎在代碼中找不到。這是最新的版本嗎? – legoscia 2014-10-02 13:40:20

+0

爲了清晰起見,我將一些io格式的東西切碎了,但它是最新的問題代碼。 – DavidH 2014-10-02 15:25:23

回答

1

的你產生代碼量是有點難以解析,但什麼最突出的是,你顯然使用原子「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}{local, ?MODULE}作爲service_worker模塊中gen_server:start_link調用的第一個參數。請記住,如果您打算啓動多個service_worker進程(因爲一次只能將一個進程註冊到一個atom),這將不起作用。