erlang OTP主管崩溃
我正在阅读Erlang文档,试图了解设置OTP gen_服务器和管理器的基础知识。每当我的gen_服务器崩溃时,我的主管也会崩溃。事实上,每当我在命令行上出错时,我的主管就会崩溃 我希望gen_服务器在崩溃时重新启动。我希望命令行错误对我的服务器组件没有任何影响。我的主管根本不应该崩溃 我正在使用的代码是一个基本的“echo服务器”,它以您发送的任何内容进行回复,还有一个管理器,它最多每分钟重启echo_服务器5次(一对一)。我的代码: echo_server.erlerlang OTP主管崩溃,erlang,otp,erlang-supervisor,gen-server,Erlang,Otp,Erlang Supervisor,Gen Server,我正在阅读Erlang文档,试图了解设置OTP gen_服务器和管理器的基础知识。每当我的gen_服务器崩溃时,我的主管也会崩溃。事实上,每当我在命令行上出错时,我的主管就会崩溃 我希望gen_服务器在崩溃时重新启动。我希望命令行错误对我的服务器组件没有任何影响。我的主管根本不应该崩溃 我正在使用的代码是一个基本的“echo服务器”,它以您发送的任何内容进行回复,还有一个管理器,它最多每分钟重启echo_服务器5次(一对一)。我的代码: echo_server.erl -module(echo_
-module(echo_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([echo/1, crash/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, echo_server}, echo_server, [], []).
%% public api
echo(Text) ->
gen_server:call(echo_server, {echo, Text}).
crash() ->
gen_server:call(echo_server, crash)..
%% behaviours
init(_Args) ->
{ok, none}.
handle_call(crash, _From, State) ->
X=1,
{reply, X=2, State}.
handle_call({echo, Text}, _From, State) ->
{reply, Text, State}.
handle_cast(_, State) ->
{noreply, State}.
-module(echo_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link(echo_sup, []).
init(_Args) ->
{ok, {{one_for_one, 5, 60},
[{echo_server, {echo_server, start_link, []},
permanent, brutal_kill, worker, [echo_server]}]}}.
echo_sup.erl
-module(echo_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([echo/1, crash/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, echo_server}, echo_server, [], []).
%% public api
echo(Text) ->
gen_server:call(echo_server, {echo, Text}).
crash() ->
gen_server:call(echo_server, crash)..
%% behaviours
init(_Args) ->
{ok, none}.
handle_call(crash, _From, State) ->
X=1,
{reply, X=2, State}.
handle_call({echo, Text}, _From, State) ->
{reply, Text, State}.
handle_cast(_, State) ->
{noreply, State}.
-module(echo_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link(echo_sup, []).
init(_Args) ->
{ok, {{one_for_one, 5, 60},
[{echo_server, {echo_server, start_link, []},
permanent, brutal_kill, worker, [echo_server]}]}}.
使用erlc*.erl
编译,下面是一个运行示例:
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-p
oll:false]
Eshell V5.7.2 (abort with ^G)
1> echo_sup:start_link().
{ok,<0.37.0>}
2> echo_server:echo("hi").
"hi"
3> echo_server:crash().
=ERROR REPORT==== 5-May-2010::10:05:54 ===
** Generic server echo_server terminating
** Last message in was crash
** When Server state == none
** Reason for termination ==
** {'function not exported',
[{echo_server,terminate,
[{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
none]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]}
=ERROR REPORT==== 5-May-2010::10:05:54 ===
** Generic server <0.37.0> terminating
** Last message in was {'EXIT',<0.35.0>,
{{{undef,
[{echo_server,terminate,
[{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
none]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[echo_server,crash]}},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}}
** When Server state == {state,
{<0.37.0>,echo_sup},
one_for_one,
[{child,<0.41.0>,echo_server,
{echo_server,start_link,[]},
permanent,brutal_kill,worker,
[echo_server]}],
{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[]}}},
5,60,
[{1273,79154,701110}],
echo_sup,[]}
** Reason for termination ==
** {{{undef,[{echo_server,terminate,
[{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
none]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[echo_server,crash]}},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
** exception exit: {{undef,
[{echo_server,terminate,
[{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
none]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[echo_server,crash]}}
in function gen_server:call/2
4> echo_server:echo("hi").
** exception exit: {noproc,{gen_server,call,[echo_server,{echo,"hi"}]}}
in function gen_server:call/2
5>
Erlang R13B01(erts-5.7.2)[source][smp:2:2][rq:2][async threads:0][kernel-p
奥利:错]
Eshell V5.7.2(使用^G中止)
1> echo\u sup:start\u link()。
{好的,}
2> echo_服务器:echo(“hi”)。
“嗨”
3> echo_服务器:崩溃()。
=错误报告===2010年5月5日::10:05:54===
**通用服务器echo_服务器终止
**最后一条消息是崩溃
**当服务器状态==无时
**终止原因==
**{'函数未导出',
[{echo_服务器,终止,
[{{badmatch,2},
[{echo_服务器,处理_调用,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
无]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]}
=错误报告===2010年5月5日::10:05:54===
**通用服务器终止
**中的最后一条消息是{'EXIT',,
{{{undef,
[{echo_服务器,终止,
[{{badmatch,2},
[{echo_服务器,处理_调用,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
无]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[echo_server,crash]},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
**当服务器状态=={state,
{,echo_sup},
一对一,
[{child,,echo_服务器,
{echo_服务器,启动_链接,[]},
永久的,残暴的杀戮,工人,
[echo_server]}],
{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[]}}},
5,60,
[{1273,79154,701110}],
echo_sup,[]]
**终止原因==
**{{{unde,[{echo_服务器,终止,
[{{badmatch,2},
[{echo_服务器,处理_调用,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
无]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[echo_server,crash]},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
**异常退出:{{unde,
[{echo_服务器,终止,
[{{badmatch,2},
[{echo_服务器,处理_调用,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
无]},
{gen_server,terminate,6},
{proc_lib,init_p_do_apply,3}]},
{gen_服务器,调用,[echo_服务器,崩溃]}
在gen_server函数中:调用/2
4> echo_服务器:echo(“hi”)。
**异常退出:{noproc,{gen_server,call,[echo_server,{echo,“hi”}]}
在gen_server函数中:调用/2
5>
我建议您调试/跟踪应用程序,以检查发生了什么。这对理解OTP中的工作方式非常有帮助
在您的情况下,您可能需要执行以下操作
启动跟踪程序:
dbg:tracer().
跟踪主管和gen_服务器的所有功能调用:
dbg:p(all,c).
dbg:tpl(echo_server, x).
dbg:tpl(echo_sup, x).
检查进程正在传递的消息:
dbg:p(new, m).
查看进程发生了什么(崩溃等):
有关跟踪的详细信息:
希望这能对现在和将来的情况有所帮助
提示:gen_服务器行为期望定义并导出回调终止/2;)
更新:在定义终止/2后,从跟踪中可以明显看出崩溃的原因。这就是它的样子:
我们(75)调用crash/0函数。这由gen_服务器(78)接收
()调用echo_服务器:崩溃()
() ! {'$gen_call',{,#Ref},crash}
()好的
()退出{{badmatch,2},
[{echo_服务器,处理_调用,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}
()注销echo_服务器
监控器(77)接收来自gen_服务器的退出信号,并执行其工作:
(<0.77.0>) << {'EXIT',<0.78.0>,
{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}
(<0.77.0>) getting_unlinked <0.78.0>
(<0.75.0>) << {'DOWN',#Ref<0.0.0.358>,process,<0.78.0>,
{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}
(<0.77.0>) call echo_server:start_link()
()从shell测试监控程序的问题是,监控程序流程链接到shell流程。当gen_服务器进程崩溃时,退出信号会传播到崩溃并重新启动的shell
为了避免这个问题
(<0.78.0>) call echo_server:terminate({{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},none)
(<0.78.0>) returned from echo_server:terminate/2 -> ok
(<0.78.0>) exit {{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}
(<0.78.0>) unregister echo_server
(<0.77.0>) << {'EXIT',<0.78.0>,
{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}
(<0.77.0>) getting_unlinked <0.78.0>
(<0.75.0>) << {'DOWN',#Ref<0.0.0.358>,process,<0.78.0>,
{{badmatch,2},
[{echo_server,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}
(<0.77.0>) call echo_server:start_link()
start_in_shell_for_testing() ->
{ok, Pid} = supervisor:start_link(echo_sup, []),
unlink(Pid).