我尝试设计一台服务器,以便在收到请求时启动临时进程。但是,当我尝试终止或终止临时进程时,出现noproc
错误。有谁能告诉我如何解决这个问题?
我收到了以下文件:
temp.erl(主要主管)
-module(temp).
-behaviour(supervisor).
-export([start_link/0, init/1]).
-export([list_children/0]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
list_children() ->
supervisor:which_children(?MODULE).
init([]) ->
process_flag(trap_exit, true),
io:format("****Main supervisor****~n"),
{ok, {{one_for_one, 5, 10},
[{temp_srv, {temp_srv, start_link, []},
permanent, infinity, worker, [temp_srv]},
{temp_sup, {temp_sup, start_link, []},
permanent, infinity, supervisor, [temp_sup]}]}}.
temp_srv.erl(服务器)
-module(temp_srv).
-behaviour(gen_server).
-export([init/1, handle_cast/2, handle_info/2, handle_call/3, terminate/2, code_change/3]).
-export([start_link/0, echo_call/1]).
-record(state, {}).
-define(SERVER, ?MODULE).
echo_call(Data) ->
gen_server:call(?SERVER, {echo, Data}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
process_flag(trap_exit, true),
{ok, #state{}}.
handle_call({echo, Data}, _From, State) ->
Result = temp_sup:assign_task({echo, Data}),
{reply, Result, State};
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
handle_cast(_Request, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_Old, State, _Extra) ->
{ok, State}.
temp_sup.erl(启动临时过程的主管)
-module(temp_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
-export([start_temp_worker/0, list_children/0, assign_task/1, select_available_children/1, select_finished_children/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
list_children() ->
supervisor:which_children(?MODULE).
init([]) ->
io:format("****Temp supervisor*****~n"),
spawn_link(fun start_pool/0),
{ok, {{simple_one_for_one, 0, 1}, [{temp_worker, {temp_worker, start_link, []}, temporary, 1000, worker, [temp_worker]}]}}.
start_pool() ->
[start_temp_worker() || _ <- lists:seq(1, 3)].
start_temp_worker() ->
supervisor:start_child(?MODULE, []).
assign_task(Data) ->
case list_children() of
[] ->
{ok, Pid} = start_temp_worker(),
gen_server:call(Pid, Data);
ChildL when is_list(ChildL) ->
case select_finished_children(ChildL) of
no_pid_to_kill -> ok;
{ok, KPid} -> gen_server:call(KPid, stop)
end,
{ok, Pid} = select_available_children(ChildL),
start_temp_worker(),
io:format("Assign task to ~p~n", [Pid]),
gen_server:call(Pid, Data)
end.
select_available_children([ChildH | ChildT]) ->
{undefined, Pid, worker, [temp_worker]} = ChildH,
case gen_server:call(Pid, check_status) of
active ->
io:format("Find available children ~p~n", [Pid]),
{ok, Pid};
running -> select_available_children(ChildT);
done -> select_available_children(ChildT)
end.
select_finished_children([ChildH | ChildT]) ->
{undefined, KPid, worker, [temp_worker]} = ChildH,
case gen_server:call(KPid, check_status) of
done ->
io:format("Find process ~p to kill~n", [KPid]),
{ok, KPid};
_ -> select_finished_children(ChildT)
end;
select_finished_children([]) -> no_pid_to_kill.
temp_worker.erl(临时过程)
-module(temp_worker).
-behaviour(gen_server).
-export([start_link/0, init/1]).
-export([handle_info/2, handle_call/3, handle_cast/2, code_change/3, terminate/2]).
-record(state, {status}).
start_link() ->
gen_server:start_link(?MODULE, [], []).
init([]) ->
process_flag(trap_exit, true),
io:format("Start temporary worker process ~p~n", [self()]),
{ok, #state{status = active}}.
handle_info(_Request, State) ->
{noreply, State}.
handle_call(check_status, _From, #state{status = Status} = State) ->
{reply, Status, State};
handle_call({echo, Msg}, _From, State) ->
io:format("~p get echo request for message ~p~n", [self(), Msg]),
{reply, Msg, State#state{status = done}};
handle_call(stop, _From, State) ->
{stop, normal, stopped, State};
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_cast(_Request, State) ->
{noreply, State}.
code_change(_Old, State, _Extra) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
一旦临时主管启动,设计应该启动三个临时过程,一旦收到请求,它将终止一个已完成工作的临时过程。
我是如何运行这些代码的:
9> temp:start_link().
****Main supervisor****
****Temp supervisor*****
Start temporary worker process <0.98.0>
{ok,<0.94.0>}
Start temporary worker process <0.99.0>
Start temporary worker process <0.101.0>
10> temp_srv:echo_call(asd).
Find available children <0.98.0>
Start temporary worker process <0.102.0>
Assign task to <0.98.0>
<0.98.0> get echo request for message asd
asd
11> temp_srv:echo_call(asd).
Find process <0.98.0> to kill
=ERROR REPORT==== 23-May-2017::23:16:34 ===
** Generic server temp_srv terminating
** Last message in was {echo,asd}
** When Server state == {state}
** Reason for termination ==
** {{noproc,{gen_server,call,[<0.98.0>,check_status]}},
[{gen_server,call,2,[{file,"gen_server.erl"},{line,204}]},
{temp_sup,select_available_children,1,[{file,"temp_sup.erl"},{line,41}]},
{temp_sup,assign_task,1,[{file,"temp_sup.erl"},{line,33}]},
{temp_srv,handle_call,3,[{file,"temp_srv.erl"},{line,21}]},
{gen_server,try_handle_call,4,[{file,"gen_server.erl"},{line,615}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,647}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]}
=ERROR REPORT==== 23-May-2017::23:16:34 ===
** Generic server temp terminating
** Last message in was {'EXIT',<0.92.0>,
{{{noproc,
{gen_server,call,[<0.98.0>,check_status]}},
{gen_server,call,[temp_srv,{echo,asd}]}},
[{gen_server,call,2,
[{file,"gen_server.erl"},{line,204}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,674}]},
{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,
{local,temp},
one_for_one,
[{child,<0.96.0>,temp_sup,
{temp_sup,start_link,[]},
permanent,infinity,supervisor,
[temp_sup]},
{child,<0.104.0>,temp_srv,
{temp_srv,start_link,[]},
permanent,infinity,worker,
[temp_srv]}],
undefined,5,10,
[-576459529],
0,temp,[]}
** Reason for termination ==
** {{{noproc,{gen_server,call,[<0.98.0>,check_status]}},
{gen_server,call,[temp_srv,{echo,asd}]}},
[{gen_server,call,2,[{file,"gen_server.erl"},{line,204}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
{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,[<0.98.0>,check_status]}},
{gen_server,call,[temp_srv,{echo,asd}]}}
in function gen_server:call/2 (gen_server.erl, line 204)
答案 0 :(得分:1)
来自error docs:
noproc - 尝试链接到不存在的进程。
错误消息显示有问题的行是:
case gen_server:call(Pid, check_status) of
这意味着Pid是一个不存在的过程。在输出中,您可以看到:
Assign task to <0.98.0>
<0.98.0> get echo request for message asd
asd
我认为这意味着过程&lt; 0.98.0&gt;已完成执行并已终止。您可以输出process_info(Pid)
来验证这一点,undefined
将返回ChildL
以查找不存在的流程。该过程位于io:format()
列表的前面。您可以使用 assign_task(Data) ->
...
case select_finished_children(ChildL) of
no_pid_to_kill -> ok;
{ok, KPid} -> gen_server:call(KPid, stop)
end,
io:format("assign_task(): ChildL: ~w~n", [ChildL]), %%<***HERE
io:format("****Info: ~w~n", [process_info(Pid)]), %%<***HERE
{ok, Pid} = select_available_children(ChildL),
声明验证:
select_available_children([ChildH | ChildT]) ->
{undefined, Pid, worker, [temp_worker]} = ChildH,
case gen_server:call(Pid, check_status) of
然后你的代码会这样做:
ChildH
<0.98.0>
包含已终止的pid Pid
,并且该pid已绑定到gen_server:call(Pid)
。然后执行noproc
,这会导致client_max_body_size
错误。