Erlang supervisor exception on starting worker

隐身守侯 提交于 2019-12-12 02:05:49

问题


I'm playing with code for supervisor trees taken from http://learnyousomeerlang.com/building-applications-with-otp but I get a noproc exception that I can't figure out when I try to get a supervisor to start the child process. This is my shell interaction:

   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)

Code is:

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

[snip]


回答1:


The volume of code you've produced is a little difficult to parse, but what stands out to me most is that you are apparently using the atom "service_worker" to refer to the process that you start.

This is all well and good if you register a process with that atom (either by calling erlang:register(service_worker, Pid) or starting the process with gen_server:start_link({local, service_worker}, ?MODULE, Args, Opts)). You appear to be doing neither, and the error message you receive supports that assessment.

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

What this error tells us is that gen_server:call was not able to find the process (noproc). The arguments to gen_server:call are included in the error message, and in the spot where one would expect to find the Pid, we find instead service_worker.

Additionally, your service_worker module appears to be started by a simple_one_for_one supervisor. Such supervisors are used when you need multiple of the same "type" of process (e.g., same callback module). Such supervisors also do not start workers on their own (you must invoke supervisor:start_child(SupPid, ExtraArgs)).

Those are the two main issues I see with your present attempt. For a quick and dirty fix, try adding {local, service_worker} or {local, ?MODULE} as the first argument to the gen_server:start_link call in the service_worker module. Please bear in mind that this will not work if you intend to start multiple service_worker processes (as only one process can be registered to an atom at a time).



来源:https://stackoverflow.com/questions/26161837/erlang-supervisor-exception-on-starting-worker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!