سؤال

أنا أعمل من خلال وثائق Erlang ، في محاولة لفهم أساسيات إعداد OTP Gen_Server والمشرف. عندما يتعطل Gen_Server الخاص بي ، يتعطل المشرف الخاص بي أيضًا. في الواقع ، كلما كان لدي خطأ في سطر الأوامر ، يتعطل مشرفي.

أتوقع إعادة تشغيل Gen_Server عند تعطله. أتوقع أن يكون أخطاء سطر الأوامر لا تحمل على الإطلاق على مكونات الخادم الخاصة بي. لا ينبغي أن يتحطم المشرف على الإطلاق.

الكود الذي أعمل معه هو "خادم صدى" أساسي يرد بكل ما ترسله ، ومشرف سيعيد تشغيل Echo_server 5 مرات في الدقيقة على الأكثر (One_for_one). رمز بلدي:

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

echo_sup.erl

-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>
هل كانت مفيدة؟

المحلول

تتمثل المشكلات في اختبار المشرفين من القذيفة على أن عملية المشرف مرتبطة بعملية shell. عندما تعطل عملية Gen_Server ، يتم نشر إشارة الخروج حتى القشرة التي تتعطل ويتم إعادة تشغيلها.

لتجنب المشكلة ، أضف شيئًا كهذا إلى المشرف:

start_in_shell_for_testing() ->
    {ok, Pid} = supervisor:start_link(echo_sup, []),
    unlink(Pid).

نصائح أخرى

أود أن أقترح عليك تصحيح/تتبع طلبك للتحقق مما يحدث. إنه أمر مفيد للغاية في فهم كيفية عمل الأشياء في OTP.

في حالتك ، قد ترغب في القيام بما يلي.

ابدأ التتبع:

dbg:tracer().

تتبع جميع وظائف الوظائف لمشرفك و gen_server الخاص بك:

dbg:p(all,c).
dbg:tpl(echo_server, x).
dbg:tpl(echo_sup, x).

تحقق من الرسائل التي تمر بها العمليات:

dbg:p(new, m).

تعرف على ما يحدث لعملياتك (تحطم ، إلخ):

dbg:p(new, p).

لمزيد من المعلومات حول التتبع:

http://www.erlang.org/doc/man/dbg.html

http://aloiroberto.wordpress.com/2009/02/23/tracing-erlang-functions/

آمل أن يساعد هذا في هذا المواقف والمواقف المستقبلية.

ملحوظة: يتوقع سلوك Gen_Server أن يتم تحديد وتصدير رد الاتصال/2 ؛)

تحديث: بعد تعريف إنهاء/2 سبب الحادث واضح من التتبع. هكذا تبدو:

نحن (75) استدعاء وظيفة Crash/0. يتم استلام هذا بواسطة Gen_Server (78).

(<0.75.0>) call echo_server:crash()
(<0.75.0>) <0.78.0> ! {'$gen_call',{<0.75.0>,#Ref<0.0.0.358>},crash}
(<0.78.0>) << {'$gen_call',{<0.75.0>,#Ref<0.0.0.358>},crash}
(<0.78.0>) call echo_server:handle_call(crash,{<0.75.0>,#Ref<0.0.0.358>},none)

اه ، مشكلة في مكالمة المقبض. لدينا diadmatch ...

(<0.78.0>) exception_from {echo_server,handle_call,3} {error,{badmatch,2}}

تسمى وظيفة الإنهاء. يخرج الخادم ويصبح غير مسجل.

(<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

يتلقى المشرف (77) إشارة الخروج من Gen_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()

حسنًا ، يحاول ... لأنه يحدث ما قاله فيليبو ...

من ناحية أخرى ، إذا كان لا بد من اختبار إعادة التشغيل من داخل وحدة التحكم ، استخدم وحدة التحكم لبدء المشرف والتحقق من PMAN لقتل العملية.

سترى أن PMAN ينعش مع نفس المشرف PID ولكن مع PIDs عامل مختلف اعتمادا على MAXR و MAXT التي وضعتها في إعادة تشغيل Strategy.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top