Domanda

Ho un supervisore principale che crea un altro supervisore:

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
    RestartStrategy = {one_for_one, 5, 600},
    ListenerSup =
            {popd_listener_sup,
            {popd_listener_sup, start_link, []},
             permanent, 2000, supervisor, [popd_listener]},

    Children = [ListenerSup],

    {ok, {RestartStrategy, Children}}.

E ho gen_server - listener.Come posso eseguire questo gen_server con popd_listener_sup supervisor, una volta creato il supervisore?

Grazie.

È stato utile?

Soluzione

Supervisore principale

-module(root_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1, shutdown/0]).

start_link() ->
     supervisor:start_link({local,?MODULE}, ?MODULE, []).

init(_Args) ->
     RestartStrategy = {one_for_one, 10, 60},
     ListenerSup = {popd_listener_sup,
          {popd_listener_sup, start_link, []},
          permanent, infinity, supervisor, [popd_listener_sup]},
     Children = [ListenerSup],
     {ok, {RestartStrategy, Children}}.    

% supervisor can be shutdown by calling exit(SupPid,shutdown)
% or, if it's linked to its parent, by parent calling exit/1.
shutdown() ->
     exit(whereis(?MODULE), shutdown).
     % or
     % exit(normal).

Se il processo figlio è un altro supervisore, Shutdown nella specifica figlio dovrebbe essere impostato su infinity per dare ampio tempo alla sottostruttura per l'arresto e Type dovrebbe essere impostato su supervisor, ed è quello che abbiamo fatto.

Supervisore bambino

-module(popd_listener_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).

start_link() ->
    supervisor:start_link({local,?MODULE}, ?MODULE, []).

init(_Args) ->
    RestartStrategy = {one_for_one, 10, 60},
    Listener = {ch1, {ch1, start_link, []},
            permanent, 2000, worker, [ch1]},
    Children = [Listener],
    {ok, {RestartStrategy, Children}}.

Qui, in una specifica figlio, impostiamo il valore di Shutdown su 2000. Un valore di timeout intero significa che il supervisore dirà al processo figlio di terminare chiamando exit(Child,shutdown) e quindi attenderà un segnale di uscita con motivo shutdown indietro dal processo figlio.

Ascoltatore

-module(ch1).
-behaviour(gen_server).

% Callback functions which should be exported
-export([init/1]).
-export([handle_cast/2, terminate/2]).

% user-defined interface functions
-export([start_link/0]).

start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init(_Args) ->
     erlang:process_flag(trap_exit, true),
     io:format("ch1 has started (~w)~n", [self()]),
     % If the initialization is successful, the function
     % should return {ok,State}, {ok,State,Timeout} ..
     {ok, []}.

handle_cast(calc, State) ->
     io:format("result 2+2=4~n"),
     {noreply, State};
handle_cast(calcbad, State) ->
     io:format("result 1/0~n"),
     1 / 0,
     {noreply, State}.

terminate(_Reason, _State) ->
     io:format("ch1: terminating.~n"),
     ok.

Dalla documentazione di Erlang / OTP:

Se gen_server fa parte di un file albero di supervisione ed è ordinato dal suo supervisore per terminare, la funzione Module:terminate(Reason, State) lo farà essere chiamato con Reason=shutdown se si applicano le seguenti condizioni:

  • il gen_server è stato impostato per intercettare i segnali di uscita e
  • la strategia di spegnimento definita nelle specifiche secondarie del supervisore
    è un valore di timeout intero, non
    brutal_kill.

Ecco perché abbiamo chiamato erlang:process_flag(trap_exit, true) in Module:init(Args).

Esempio di esecuzione

Avvio del supervisore principale:

1> root_sup:start_link().
ch1 has started (<0.35.0>)
{ok,<0.33.0>}

Il supervisore principale viene eseguito e avvia automaticamente i suoi processi figlio, nel nostro caso il supervisore figlio. Il supervisore figlio a sua volta avvia i suoi processi figlio; abbiamo un solo figlio nel nostro caso, ch1.

Facciamo in modo che ch1 valuti il ​​codice normale:

2> gen_server:cast(ch1, calc).
result 2+2=4
ok

Ora un pessimo codice:

3> gen_server:cast(ch1, calcbad).
result 1/0
ok
ch1: terminating.

=ERROR REPORT==== 31-Jan-2011::01:38:44 ===
** Generic server ch1 terminating 
** Last message in was {'$gen_cast',calcbad}
** When Server state == []
** Reason for termination == 
** {badarith,[{ch1,handle_cast,2},
              {gen_server,handle_msg,5},
              {proc_lib,init_p_do_apply,3}]}
ch1 has started (<0.39.0>)
4> exit(normal).
ch1: terminating.
** exception exit: normal

Come puoi vedere, il processo figlio ch1 è stato riavviato dal supervisore figlio popd_listener_sup (avviso ch1 has started (<0.39.0>)).

Poiché la nostra shell e il supervisore di root sono collegati in modo bidirezionale (chiama supervisor:start_link, non supervisor:start nella funzione del supervisore di root start_link/0), exit(normal) ha provocato l'arresto del supervisore di root, ma i suoi processi figli hanno avuto del tempo per ripulire.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top