يبدأ المشرف الديناميكي Erlang gen_server
-
27-10-2019 - |
سؤال
لدي مشرف جذر يقوم بإنشاء مشرف آخر:
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}}.
ولدي gen_server - المستمع.كيف يمكنني تشغيل هذا gen_server مع popd_listener_sup
المشرف، عندما خلق المشرف؟
شكرًا لك.
المحلول
مشرف الجذر
-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).
إذا كانت العملية الفرعية مشرفًا آخر، Shutdown
في مواصفات الطفل يجب ضبطها على infinity
لمنح الشجرة الفرعية وقتًا كافيًا لإيقاف التشغيل، و Type
يجب ضبطه على supervisor
, ، وهذا ما فعلناه.
مشرف الطفل
-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}}.
هنا، في مواصفات الطفل، قمنا بتعيين قيمة Shutdown
ل 2000
.تعني قيمة المهلة الصحيحة أن المشرف سيخبر العملية الفرعية بالإنهاء عن طريق الاتصال exit(Child,shutdown)
ثم انتظر إشارة الخروج مع سبب إيقاف التشغيل من العملية الفرعية.
المستمع
-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.
من وثائق Erlang/OTP:
إذا كان Gen_Server جزءًا من شجرة الإشراف وأمر من قبل المشرف على إنهاء ، فإن الوظيفة
Module:terminate(Reason, State)
سيتم استدعاؤه معReason=shutdown
إذا تم تطبيق الشروط التالية:
- ال
gen_server
تم ضبطه لاحتجاز إشارات الخروج، و- استراتيجية إيقاف التشغيل كما هو محدد في مواصفات الطفل الخاصة بالمشرف
هي قيمة مهلة عدد صحيح، وليس
وحشية_قتل.
لهذا السبب اتصلنا erlang:process_flag(trap_exit, true)
في Module:init(Args)
.
تشغيل العينة
بدء المشرف الجذر:
1> root_sup:start_link().
ch1 has started (<0.35.0>)
{ok,<0.33.0>}
يتم تشغيل المشرف الجذر ويبدأ تلقائيًا عملياته الفرعية، المشرف الفرعي في حالتنا.يبدأ مشرف الطفل بدوره عملياته الفرعية؛لدينا طفل واحد فقط في حالتنا، ch1
.
هيا نصنع ch1
تقييم الكود العادي:
2> gen_server:cast(ch1, calc).
result 2+2=4
ok
الآن بعض التعليمات البرمجية السيئة:
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
كما ترون عملية الطفل ch1
تم إعادة تشغيله من قبل مشرف الطفل popd_listener_sup
(يلاحظ ch1 has started (<0.39.0>)
).
نظرًا لأن مشرف الصدفة والجذر الخاص بنا مرتبطان ثنائي الاتجاه (call supervisor:start_link
, ، لا supervisor:start
في وظيفة المشرف الجذر start_link/0
), exit(normal)
أدى إلى إيقاف تشغيل المشرف الجذري، ولكن العمليات الفرعية الخاصة به كان لديها بعض الوقت للتنظيف.