2010-05-05 23 views
8

Bir OTP gen_server ve süpervizör kurmanın temellerini anlamaya çalışmak için Erlang belgeleri üzerinde çalışıyorum. Gen_serverim her ne zaman çökerse, amirim de çöker. Aslında, komut satırında bir hatam olduğunda, amirim çöker.erlang OTP Süpervizör çöküyor

Gen_server'ın kilitlendiğinde yeniden başlatılmasını bekliyorum. Komut satırı hatalarım, sunucu bileşenlerimde numaralı numaralı rulmana sahip olmamasını beklerim. Amirim hiç çökmemeli.

Çalıştığım kod, gönderdiğiniz her şeyle yanıt veren temel bir "echo sunucusu" ve echo_server'i dakikada en çok 5 kez yeniden başlatan bir denetleyici (one_for_one). Kodum:

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 kullanarak Derleyen ve burada örnek bir çalışma var:

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> 

cevap

15

Kabuktan gelen sorun testi denetleyicileri, denetim sürecinin kabuk işlemiyle bağlantılı olması. Gen_server işlemi kilitlendiğinde, çıkış sinyali, çöken ve yeniden başlatılan kabuğa kadar çoğaltılır.

süpervizöre böyle bir şey eklemek sorunu önlemek için:

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

Bunu geliştirirken veya hata ayıklarken sadece geçerli bir yaklaşım olduğunu ekleyebilirim. Canlı bir üretim sisteminde, normal bir denetim ağacında standart bir OTP uygulamasında kodunuzu denemek ve sarmak daha iyidir. –

+0

Tam olarak benzer bir sorun vardı, unlink (Pid) çalışır. – pranjal

+0

Ben süredir erlang kod yazmadım http://stackoverflow.com/questions/6720472/erlang-and-process-flagtrap-exit-true buraya bir göz atın, ama eğer iyi hatırlıyorum, olup bitenler Bu, gen_server çöktüğünde, çıkış sinyali tüm bağlantılı işlemlere yayılır. Çıkış sinyalini yukarıdaki bağlantıda olduğu gibi kapatabilirsiniz, ancak neredeyse hiç yapmak istemezsiniz. Erlang felsefeye çarpmasın. – filippo

9

Ben wou Neler olup bittiğini kontrol etmek için uygulamanızı hata ayıklama/izleme uygulamanızı öneririm. İşlerin OTP'de nasıl çalıştığını anlamada çok yardımcı oluyor.

Durumunuzda, aşağıdakileri yapmak isteyebilirsiniz.

dbg:tracer(). 

İz tüm işlev Amirinizle çağrısı ve gen_server:

dbg:p(new, m). 

neler olduğuna bakın: süreçleri geçiyoruz mesajlar

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

Kontrol

izleyici Başlangıç ​​

Süreçlerinize (çökme, vb.):

izleme hakkında daha fazla bilgi için
dbg:p(new, p). 

: bu ve gelecekteki durumlar için yardımcı olabilir

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

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

Umut.

İPUCU: gen_server davranışı geri arama/2 tanımlandığı gibidir ve ihraç edilecek sona bekliyor;)

Update:tanımı çökmesi sebep/2 sona sonra belirgindir izinden. Göründüğü gibi:

Biz (75) kilitlenme/0 işlevini çağırıyoruz. Bu gen_server tarafından alınır (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) 

Uh, tutamağındaki sorun. Bir badmatch ...

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

sonlandırmak fonksiyonu denir var. Sunucu çıkar ve kayıtsız olur.

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

Danışman (77) gen_server çıkış sinyali alacak ve işini yapar:

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

Eh, çalışır ... o Filippo dedi ne olur bu yana ...

+0

teşekkürler. "Tanımlanmadı ... sonlandır" işlevi beni de şaşırttı. Gen_server davranışı *, echo_server çıkışları yakalamadığından, sonlandırmanın sona ermesini beklememelidir. Bu, yine de dokümanlar başına; OTP'nin kodunu henüz okumadım. – drfloob

+0

Sonlandırmayı/2'yi tanımlamak ve dışa aktarmak, UNDEF'i kaldırarak, kazanın gerçek nedenini gösterecektir (2'de hatalı eşleşme). Bağlayıcı şeyler başka bir hikaye ... Şimdi biraz kafam karıştı. Tam olarak ne demek istiyorsun? "Echo_server çıkışları yakalamadığından, gen_server davranışının sonlandırılmasını beklememesi gerekir" ile ne demek istiyorsun? –

+0

Cevabı güncelledim. Bir göz atın. –

1

Öte yandan, tüm yeniden başlatma-strateji de konsolunun içinden test edilecek varsa, kullanım konsolu danışmanı ve denetimini başlatmak için süreci öldürmek için pman ile.

O pman görecekti aynı amiri Pid ile fakat farklı işçisi PID Eğer yeniden başlatma-stratejisinde belirledik MaxR ve MaxT bağlı olan yeniler. ayıklama ipuçları için