Erlang主管工作人员例外 [英] Erlang supervisor exception on starting worker

查看:174
本文介绍了Erlang主管工作人员例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  1>应用:开始(试验)。 
根管理员init
ok
2> test_sup:start_service(service_sup,{service_worker,start_link,[]})。
{ok,< 0.39.0>}
工作主管初始化(M:service_worker,F:start_link,A:[])

3> test_app:运行(service_worker,[])。
服务器运行:(name:service_worker args:[])
**异常退出:{noproc,{gen_server,call,[service_worker,{run,[]}]}}
函数gen_server:call / 2(gen_server.erl,第182行)

代码是:

  -module(test_app)。 
-behaviour(应用程序)。
-export([start / 2,stop / 1,run / 2])。

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


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

=====

   - 模(test_sup)。 

-behaviour(主管)。

-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() - >
主管: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服务主管(名称:〜p,MFA:〜p):,[名称,MFA]),
主管:start_child(service,ChildSpec)。
[snip]

====

  -module(service_sup)。 
-export([start_link / 2,init / 1])。
-behaviour(主管)。

start_link(Name,MFA) - >
主管: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]}]}}。

========

   - 模(worker_sup)。 
-export([start_link / 1,init / 1])。
-behaviour(主管)。

start_link(MFA) - >
主管:start_link(?MODULE,MFA)。

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

===

   - 模(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]},
永久,
10000,
主管,
[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 - > %%不是我们的责任
{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]

解决方案

您生成的代码量有点难以解析,但最引人注目的是,您显然使用service_worker原子来引用您开始的进程。 / p>

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

  **异常退出:{noproc,{ gen_server,call,[service_worker,{run,[]}]}}函数gen_server中的
:call / 2(gen_server.erl,第182行)

这个错误告诉我们的是,$ code> gen_server:call 无法找到进程( noproc )。 gen_server:call 的参数包含在错误消息中,并且在预期找到 Pid ,我们找到 service_worker



此外,您的 service_worker 模块似乎由 simple_one_for_one 主管启动。当您需要多个相同的类型过程(例如,相同的回调模块)时,将使用这样的主管。这样的主管也不会自己启动工作(你必须调用主管:start_child(SupPid,ExtraArgs))。



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


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]

解决方案

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

这篇关于Erlang主管工作人员例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆