Erlang Dynamic Supervisor startet gen_server
-
27-10-2019 - |
Frage
Ich habe einen Root-Supervisor, der einen anderen Supervisor erstellt:
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}}.
Und ich habe gen_server - Listener.Wie kann ich diesen gen_server mit dem popd_listener_sup
-Supervisor ausführen, wenn der Supervisor erstellt wurde?
Danke.
Lösung
Root-Supervisor
-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).
-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).
Wenn der untergeordnete Prozess ein anderer Supervisor ist, sollte Shutdown
in der untergeordneten Spezifikation auf infinity
gesetzt werden, damit der Teilbaum ausreichend Zeit zum Herunterfahren hat, und Type
sollte auf supervisor
gesetzt werden, und das haben wir getan.
Kinderbetreuer
-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}}.
-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}}.
Hier setzen wir in einer untergeordneten Spezifikation den Wert von Shutdown
auf 2000
. Ein ganzzahliger Timeout-Wert bedeutet, dass der Supervisor den untergeordneten Prozess durch Aufrufen von exit(Child,shutdown)
zum Beenden auffordert und dann auf ein Exit-Signal wartet, dessen Grund vom untergeordneten Prozess zurückgesetzt wird.
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.
-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.
Aus der Erlang / OTP-Dokumentation:
Wenn der gen_server Teil von a ist Überwachungsbaum und wird von seiner bestellt Supervisor zu beenden, die Funktion
Module:terminate(Reason, State)
wird mitReason=shutdown
aufgerufen werden, wenn Es gelten folgende Bedingungen:
- Der
gen_server
wurde so eingestellt, dass Ausgangssignale abgefangen werden, und- die Abschaltstrategie, wie sie in der untergeordneten Spezifikation des Supervisors definiert ist
ist ein ganzzahliger Timeout-Wert, nicht
brutal_kill.Deshalb haben wir
erlang:process_flag(trap_exit, true)
inModule:init(Args)
genannt.Probelauf
Starten des Root-Supervisors:
1> root_sup:start_link(). ch1 has started (<0.35.0>) {ok,<0.33.0>}
Der Root-Supervisor wird ausgeführt und startet automatisch seine untergeordneten Prozesse, in unserem Fall den untergeordneten Supervisor. Der Child Supervisor wiederum startet seine untergeordneten Prozesse. In unserem Fall haben wir nur ein Kind,
ch1
.Lassen Sie
ch1
den normalen Code auswerten:2> gen_server:cast(ch1, calc). result 2+2=4 ok
Nun ein schlechter 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
Wie Sie vielleicht sehen, wurde der
ch1
des untergeordneten Prozesses vompopd_listener_sup
des untergeordneten Supervisors neu gestartet (beachten Sie dench1 has started (<0.39.0>)
).Da unsere Shell und unser Root-Supervisor bidirektional miteinander verbunden sind (rufen Sie
supervisor:start_link
auf, nichtsupervisor:start
in der Root-Supervisor-Funktionstart_link/0
), führteexit(normal)
zum Herunterfahren des Root-Supervisors, aber die untergeordneten Prozesse hatten einige Zeit zum Bereinigen.