为什么我的主管要辞职? [英] Why my supervisor terminating?
问题描述
我是OTP的新手,我试图创建一个简单的示例来了解主管的行为:
I'm very new to OTP, I'm trying to create simple example to understand supervisor behaviour:
这是简单的增量服务器
-module( inc_serv ).
-behaviour( gen_server ).
-export( [ start/0, inc/1, stop/0 ] ).
-export( [ init/1, handle_call/3, terminate/2 ] ).
start() ->
gen_server:start_link( { local, ?MODULE }, ?MODULE, no_args, [] ).
stop() ->
gen_server:call( ?MODULE, stop ).
inc( Num ) ->
gen_server:call( ?MODULE, { num, Num } ).
init( no_args ) ->
io:format( "~p~n", [ "Increment server started :)" ] ),
{ ok, no_state }.
handle_call( { num, Num }, _From, no_state ) ->
{ reply, Num + 1, no_state };
handle_call( stop, _From, no_state ) ->
{ stop, normal, ok, no_state }.
terminate( Reason, no_state ) ->
io:format( "~p~n", [ "Increment server stopped" ] ).
我想通过此模块对其进行监督:
And I'd like to make it supervised by this module:
-module( supervisor_inc ).
-behaviour( supervisor ).
-export( [ start/0 ] ).
-export( [ init/1 ] ).
start() ->
supervisor:start_link( { local, ?MODULE }, ?MODULE, no_args ).
init( no_args ) ->
process_flag( trap_exit, true ),
Supervisor_Spec = { one_for_one, 1, 1 },
IncServ_Spec = {
inc_serv,
{ inc_serv, start, [] },
permanent, 2000, worker, [ inc_serv ] },
{ ok, { Supervisor_Spec, [ IncServ_Spec ] } }.
之后,我在erlang shell中执行了下一步:
After that I've performed in erlang shell next steps:
1>
1> c(inc_serv).
{ok,inc_serv}
2>
2> c(supervisor_inc).
{ok,supervisor_inc}
3>
3> supervisor_inc:start().
"Increment server started :)"
{ok,<0.43.0>}
4>
4> inc_serv:inc( 7 ).
8
5> inc_serv:inc( 8 ).
9
在此之后,我尝试了下一个步骤(如我预期的那样,我遇到了错误):
After this I've tried next (as I expected I've got error):
6> inc_serv:inc( bad_arg ).
"Increment server stopped"
"Increment server started :)"
=ERROR REPORT==== 23-Aug-2012::19:32:06 ===
** Generic server inc_serv terminating
** Last message in was {num,bad_arg}
** When Server state == no_state
** Reason for termination ==
** {badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}
=ERROR REPORT==== 23-Aug-2012::19:32:06 ===
** Generic server supervisor_inc terminating
** Last message in was {'EXIT',<0.31.0>,
{{{badarith,
[{inc_serv,handle_call,3,
[{file,"inc_serv.erl"},{line,22}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
{gen_server,call,[inc_serv,{num,bad_arg}]}},
[{gen_server,call,2,
[{file,"gen_server.erl"},{line,180}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,576}]},
{shell,exprs,7,[{file,"shell.erl"},{line,668}]},
{shell,eval_exprs,7,
[{file,"shell.erl"},{line,623}]},
{shell,eval_loop,3,
[{file,"shell.erl"},{line,608}]}]}}
** When Server state == {state,
{local,supervisor_inc},
one_for_one,
[{child,<0.48.0>,inc_serv,
{inc_serv,start,[]},
permanent,2000,worker,
[inc_serv]}],
undefined,1,1,
[{1345,739526,107495}],
supervisor_inc,no_args}
** Reason for termination ==
** {{{badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
{gen_server,call,[inc_serv,{num,bad_arg}]}},
[{gen_server,call,2,[{file,"gen_server.erl"},{line,180}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,576}]},
{shell,exprs,7,[{file,"shell.erl"},{line,668}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}
** exception exit: {{badarith,[{inc_serv,handle_call,3,
[{file,"inc_serv.erl"},{line,22}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
{gen_server,call,[inc_serv,{num,bad_arg}]}}
in function gen_server:call/2 (gen_server.erl, line 180)
在此之后,我期望-我的主管重新启动inc_serv
.但事实并非如此:
After this I've expected - my supervisor to restart inc_serv
. But it didn't:
7> inc_serv:inc( 8 ).
** exception exit: {noproc,{gen_server,call,[inc_serv,{num,8}]}}
in function gen_server:call/2 (gen_server.erl, line 180)
您能帮我了解发生了什么吗?以及我该如何重写我的主管,以使其能够重新启动inc_serv
Could you help me to understand what happened? And how should I rewrite my supervisor, to make it able to restart inc_serv
谢谢
推荐答案
这实际上是一种竞争条件.
This is actually a kind of race condition.
您可能知道,Erlang shell本身是一个正常的Erlang进程.从外壳启动主管时,主管已链接到外壳(因为您使用了supervisor:start_link/3
).
As you might know, the Erlang shell itself is a normal Erlang process. When you start your supervisor from the shell, the supervisor is linked to the shell (because you use supervisor:start_link/3
).
当您调用gen_server进程时,该进程将崩溃(并且由主管正确地重新启动,如随后的"Increment server started :)"
输出所示).
When you call your gen_server process, that process crashes (and is correctly restarted by the supervisor, as you can see by the subsequent "Increment server started :)"
output).
但是,同时,您对gen_server:call/2
的调用将导致相同的崩溃(在调用过程中gen_server崩溃将通过gen_server:call/2
函数发出相同的崩溃).然后,这会使连接到您的主管的shell进程崩溃,而该进程又由于相同的原因(badarith
)崩溃.
However, at the same time, your call to gen_server:call/2
will result in the same crash (a gen_server crashing during the call will emit the same crash through the gen_server:call/2
function). This then crashes the shell process, which is linked to your supervisor, which in turn crashes with the same reason (badarith
).
基本上,您的主管在忠诚地重新启动gen_server之后,就被shell进程所刺伤.像这样:
Basically, your supervisor is backstabbed by your shell process, after it loyally restarted your gen_server. Like so:
+---------(6)exit----------+ +---------(5)restart---------+
| | | |
| v | v
Shell ---(1)start_link---> supervisor ---(2)start_link---> gen_server
| ^ ^ | ^ | ^
| | | | | | |
| | | +---------(7)exit---------+ | |
| | | | |
| +-------------------------+--------------(4)exit------------+ |
| |
+---------------------------(3)call--------------------------------+
您可以通过在外壳程序中调用catch inc_serv:inc(bad_arg).
来避免这种情况:
You can avoid this by calling catch inc_serv:inc(bad_arg).
in your shell:
90> inc_serv:inc(7).
8
91> catch inc_serv:inc(bad_arg).
"Increment server stopped"
=ERROR REPORT==== 23-Aug-2012::22:10:02 ===
** Generic server inc_serv terminating
** Last message in was {num,bad_arg}
** When Server state == no_state
** Reason for termination ==
** {badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,20}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}
"Increment server started :)"
{'EXIT',{{badarith,[{inc_serv,handle_call,3,
[{file,"inc_serv.erl"},{line,20}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
{gen_server,call,[inc_serv,{num,bad_arg}]}}}
92> inc_serv:inc(7).
8
这篇关于为什么我的主管要辞职?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!