Erlang superviseur dynamique début gen_server
-
27-10-2019 - |
Question
Je superviseur racine qui crée un autre superviseur:
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}}.
Et j'ai gen_server - auditeur. Comment puis-je exécuter ce gen_server avec le superviseur de popd_listener_sup
, quand le superviseur créé?
Merci.
La solution
superviseur racine
-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).
Si le processus de l'enfant est un autre superviseur, Shutdown
dans la spécification de l'enfant doit être réglé sur infinity
pour donner la sous-arborescence suffisamment de temps à l'arrêt, et Type
doit être réglé sur supervisor
, et que ce que nous avons fait.
superviseur enfant
-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}}.
Ici, dans un cahier des charges de l'enfant, nous avons mis en valeur Shutdown
à 2000
. Un moyen de délai d'attente entier que le superviseur dit que le processus de l'enfant de mettre fin en appelant exit(Child,shutdown)
puis attendre un signal de sortie avec le dos d'arrêt raison du processus de l'enfant.
Listener
-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.
De la documentation Erlang / OTP:
Si la gen_server fait partie d'un arbre de surveillance et est commandé par son superviseur de mettre fin, la fonction volonté de
Module:terminate(Reason, State)
être appelé avecReason=shutdown
si les conditions suivantes:
- le
gen_server
a été fixé à des signaux de sortie du piège, et- la stratégie d'arrêt tel que défini dans la spécification de enfant
du superviseur est une valeur de délai d'entier, et non pas
brutal_kill.
Voilà pourquoi nous appelions erlang:process_flag(trap_exit, true)
dans Module:init(Args)
.
run échantillon
Démarrage du superviseur racine:
1> root_sup:start_link().
ch1 has started (<0.35.0>)
{ok,<0.33.0>}
superviseur racine est exécuté et démarre automatiquement ses processus enfants, superviseur des enfants dans notre cas. superviseur de l'enfant à son tour commence ses processus enfants; nous avons un seul enfant dans notre cas, ch1
.
faire la ch1
Let évaluer le code normal:
2> gen_server:cast(ch1, calc).
result 2+2=4
ok
Maintenant, certains mauvais code:
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
Comme vous pouvez le voir processus enfant ch1
a été repris par le superviseur de l'enfant popd_listener_sup
(avis ch1 has started (<0.39.0>)
).
Depuis notre coquille et le superviseur racine sont bidirectionnellement liées (appel supervisor:start_link
, non supervisor:start
dans la fonction superviseur racine start_link/0
), exit(normal)
a donné lieu à l'arrêt du superviseur racine, mais ses processus enfants ont un peu de temps à nettoyer.