Erlang Language
निदेशक
खोज…
परिचय
Erlang प्रक्रियाओं के लिए लचीला, तेज और शक्तिशाली पर्यवेक्षक पुस्तकालय।
टिप्पणियों
चेतावनी
- अपनी योजना में
'count'=>infinityऔर तत्वrestartका उपयोग न करें।
पसंद:
Childspec = #{id => foo
,start => {bar, baz, [arg1, arg2]}
,plan => [restart]
,count => infinity}.
यदि क्रैश के बाद आपकी प्रक्रिया शुरू नहीं हुई, तो निदेशक ताला लगाएगा और आपकी प्रक्रिया को infinity बार फिर से शुरू करेगा! आप उपयोग कर रहे हैं infinity के लिए 'count' , हमेशा उपयोग {restart, MiliSeconds} में 'plan' के बजाय restart ।
- यदि आपके पास योजनाएं हैं:
Childspec1 = #{id => foo
,start => {bar, baz}
,plan => [restart,restart,delete,wait,wait, {restart, 4000}]
,count => infinity}.
Childspec2 = #{id => foo
,start => {bar, baz}
,plan => [restart,restart,stop,wait, {restart, 20000}, restart]
,count => infinity}.
Childspec3 = #{id => foo
,start => {bar, baz}
,plan => [restart,restart,stop,wait, {restart, 20000}, restart]
,count => 0}.
Childspec4 = #{id => foo
,start => {bar, baz}
,plan => []
,count => infinity}.
के बाकी delete में तत्व Childspec1 और के बाकी stop में तत्व Childspec2 का मूल्यांकन कभी नहीं होगा!
Childspec3 आप अपनी योजना को 0 बार चलाना चाहते हैं!
ChildSpec4 आपके पास infinity बार चलाने की कोई योजना नहीं है!
- जब आप
release_handlerका उपयोग करके किसी रिलीज़ को अपग्रेड करते हैं, तोrelease_handlerकॉलsupervisor:get_callback_module/1इसके कॉलबैक मॉड्यूल को लाने के लिए।
OTP में <19get_callback_module/1अपने कॉलबैक मॉड्यूल देने के लिए पर्यवेक्षक आंतरिक राज्य रिकॉर्ड का उपयोग करता है। हमारे निदेशक को पर्यवेक्षक आंतरिक राज्य रिकॉर्ड के बारे में नहीं पता है, फिरsupervisor:get_callback_module/1निर्देशक के काम नहीं करता है।
अच्छी खबर यह है कि ओटीपी में = = 19supervisor:get_callback_module/1पूरी तरह से निर्देशक के साथ काम करता है :)।
1> foo:start_link().
{ok,<0.105.0>}
2> supervisor:get_callback_module(foo_sup).
foo
3>
डाउनलोड
Pouriya@Jahanbakhsh ~ $ git clone https://github.com/Pouriya-Jahanbakhsh/director.git
संकलन
ध्यान दें कि OTP> = 19 आवश्यक है (यदि आप इसे release_handler का उपयोग करके अपग्रेड करना चाहते हैं)।
director जाएं और rebar या rebar3 उपयोग करें।
Pouriya@Jahanbakhsh ~ $ cd director
rebar
Pouriya@Jahanbakhsh ~/director $ rebar compile ==> director_test (compile) Compiled src/director.erl Pouriya@Jahanbakhsh ~/director $
rebar3
Pouriya@Jahanbakhsh ~/director $ rebar3 compile ===> Verifying dependencies... ===> Compiling director Pouriya@Jahanbakhsh ~/director $
यह काम किस प्रकार करता है
निदेशक को एक कॉलबैक मॉड्यूल (जैसे ओटीपी पर्यवेक्षक) की आवश्यकता होती है।
कॉलबैक मॉड्यूल में आपको फ़ंक्शन init/1 निर्यात करना चाहिए।
क्या init/1 वापस आना चाहिए? रुको, मैं चरण दर चरण समझाता हूँ।
-module(foo).
-export([init/1]).
init(_InitArg) ->
{ok, []}.
निदेशक निर्देशिका में foo.erl में उपरोक्त कोड सहेजें और Erlang शेल पर जाएं।
यदि आपने इसे संकलित करने के लिए rebar का उपयोग किया है और यदि आपने rebar3 उपयोग किया है तो rebar3 shell उपयोग करने के लिए erl -pa ./ebin उपयोग करें।
Erlang/OTP 19 [erts-8.3] [source-d5c06c6] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V8.3 (abort with ^G)
1> c(foo).
{ok,foo}
2> Mod = foo.
foo
3> InitArg = undefined. %% i don't need it yet.
undefined
4> {ok, Pid} = director:start_link(Mod, InitArg).
{ok,<0.112.0>}
5>
अब हमारे पास बच्चों के बिना एक पर्यवेक्षक है।
अच्छी खबर यह है कि निर्देशक पूर्ण ओटीपी / पर्यवेक्षक एपीआई के साथ आता है और इसमें इसकी उन्नत विशेषताएं और विशिष्ट दृष्टिकोण भी हैं।
5> director:which_children(Pid). %% You can use supervisor:which_children(Pid) too :)
[]
6> director:count_children(Pid). %% You can use supervisor:count_children(Pid) too :)
[{specs,0},{active,0},{supervisors,0},{workers,0}]
7> director:get_pids(Pid). %% You can NOT use supervisor:get_pids(Pid) because it hasn't :D
[]
ठीक है, मैं सरल gen_server और इसे हमारे निर्देशक को दूंगा।
-module(bar).
-behaviour(gen_server).
-export([start_link/0
,init/1
,terminate/2]). %% i am not going to use handle_call, handle_cast ,etc.
start_link() ->
gen_server:start_link(?MODULE, null, []).
init(_GenServerInitArg) ->
{ok, state}.
terminate(_Reason, _State) ->
ok.
उपरोक्त कोड को bar.erl में bar.erl और शेल पर वापस आ गया।
8> c(bar).
bar.erl:2: Warning: undefined callback function code_change/3 (behaviour 'gen_server')
bar.erl:2: Warning: undefined callback function handle_call/3 (behaviour 'gen_server')
bar.erl:2: Warning: undefined callback function handle_cast/2 (behaviour 'gen_server')
bar.erl:2: Warning: undefined callback function handle_info/2 (behaviour 'gen_server')
{ok,bar}
%% You should define unique id for your process.
9> Id = bar_id.
bar_id
%% You should tell diector about start module and function for your process.
%% Should be tuple {Module, Function, Args}.
%% If your start function doesn't need arguments (like our example)
%% just use {Module, function}.
10> start = {bar, start_link}.
{bar,start_link}
%% What is your plan for your process?
%% I asked you some questions at the first of this README file.
%% Plan should be an empty list or list with n elemenst.
%% Every element can be one of
%% 'restart'
%% 'delete'
%% 'stop'
%% {'stop', Reason::term()}
%% {'restart', Time::pos_integer()}
%% for example my plan is:
%% [restart, {restart, 5000}, delete]
%% In first crash director will restart my process,
%% after next crash director will restart it after 5000 mili-seconds
%% and after third crash director will not restart it and will delete it
11> Plan = [restart, {restart, 5000}, delete].
[restart,{restart,5000},delete]
%% What if i want to restart my process 500 times?
%% Do i need a list with 500 'restart's?
%% No, you just need a list with one element, I'll explain it later.
12> Childspec = #{id => Id
,start => Start
,plan => Plan}.
#{id => bar_id,
plan => [restart,{restart,5000},delete],
start => {bar,start_link}}
13> director:start_child(Pid, Childspec). %% You can use supervisor:start_child(Pid, ChildSpec) too :)
{ok,<0.160.0>}
14>
इसकी जाँच करें
14> director:which_children(Pid).
[{bar_id,<0.160.0>,worker,[bar]}]
15> director:count_children(Pid).
[{specs,1},{active,1},{supervisors,0},{workers,1}]
%% What was get_pids/1?
%% It will returns all RUNNING ids with their pids.
16> director:get_pids(Pid).
[{bar_id,<0.160.0>}]
%% We can get Pid for specific RUNNING id too
17> {ok, BarPid1} = director:get_pid(Pid, bar_id).
{ok,<0.160.0>}
%% I want to kill that process
18> erlang:exit(BarPid1, kill).
true
%% Check all running pids again
19> director:get_pids(Pid).
[{bar_id,<0.174.0>}] %% changed (restarted)
%% I want to kill that process again
%% and i will check children before spending time
20> {ok, BarPid2} = director:get_pid(Pid, bar_id), erlang:exit(BarPid2, kill).
true
21> director:get_pids(Pid).
[]
22> director:which_children(Pid).
[{bar_id,restarting,worker,[bar]}] %% restarting
23> director:get_pid(Pid, bare_id).
{error,not_found}
%% after 5000 ms
24> director:get_pids(Pid).
[{bar_id,<0.181.0>}]
25> %% Yoooohoooooo
मैंने उन्नत सुविधाओं का उल्लेख किया, वे क्या हैं? Childspec नक्शे के लिए अन्य स्वीकार्य कुंजियाँ देखें।
-type childspec() :: #{'id' => id()
,'start' => start()
,'plan' => plan()
,'count' => count()
,'terminate_timeout' => terminate_timeout()
,'type' => type()
,'modules' => modules()
,'append' => append()}.
%% 'id' is mandatory and can be any Erlang term
-type id() :: term().
%% Sometimes 'start' is optional ! just wait and read carefully
-type start() :: {module(), function()} % default Args is []
| mfa().
%% I explained 'restart', 'delete' and {'restart', MiliSeconds}
%% 'stop': director will crash with reason {stop, [info about process crash]}.
%% {'stop', Reason}: director exactly will crash with reason Reason.
%% 'wait': director will not restart process,
%% but you can restart it using director:restart_child/2 and you can use supervisor:restart_child/2 too.
%% fun/2: director will execute fun with 2 arguments.
%% First argument is crash reason for process and second argument is restart count for process.
%% Fun should return terms like other plan elements.
%% Default plan is:
%% [fun
%% (normal, _RestartCount) ->
%% delete;
%% (shutdown, _RestartCount) ->
%% delete;
%% ({shutdown, _Reason}, _RestartCount) ->
%% delete;
%% (_Reason, _RestartCount) ->
%% restart
%% end]
-type plan() :: [plan_element()] | [].
-type plan_element() :: 'restart'
| {'restart', pos_integer()}
| 'wait'
| 'stop'
| {'stop', Reason::term()}
| fun((Reason::term()
,RestartCount::pos_integer()) ->
'restart'
| {'restart', pos_integer()}
| 'wait'
| 'stop'
| {'stop', Reason::term()}).
%% How much time you want to run plan?
%% Default value of 'count' is 1.
%% Again, What if i want to restart my process 500 times?
%% Do i need a list with 500 'restart's?
%% You just need plan ['restart'] and 'count' 500 :)
-type count() :: 'infinity' | non_neg_integer().
%% How much time director should wait for process termination?
%% 0 means brutal kill and director will kill your process using erlang:exit(YourProcess, kill).
%% For workers default value is 1000 mili-seconds and for supervisors default value is 'infinity'.
-type terminate_timeout() :: 'infinity' | non_neg_integer().
%% default is 'worker'
-type type() :: 'worker' | 'supervisor'.
%% Default is first element of 'start' (process start module)
-type modules() :: [module()] | 'dynamic'.
%% :)
%% Default value is 'false'
%% I'll explan it
-type append() :: boolean().
foo मॉड्यूल संपादित करें:
-module(foo).
-export([start_link/0
,init/1]).
start_link() ->
director:start_link({local, foo_sup}, ?MODULE, null).
init(_InitArg) ->
Childspec = #{id => bar_id
,plan => [wait]
,start => {bar,start_link}
,count => 1
,terminate_timeout => 2000},
{ok, [Childspec]}.
फिर से एरलैंग शेल पर जाएं:
1> c(foo).
{ok,foo}
2> foo:start_link().
{ok,<0.121.0>}
3> director:get_childspec(foo_sup, bar_id).
{ok,#{append => false,count => 1,id => bar_id,
modules => [bar],
plan => [wait],
start => {bar,start_link,[]},
terminate_timeout => 2000,type => worker}}
4> {ok, Pid} = director:get_pid(foo_sup, bar_id), erlang:exit(Pid, kill).
true
5> director:which_children(foo_sup).
[{bar_id,undefined,worker,[bar]}] %% undefined
6> director:count_children(foo_sup).
[{specs,1},{active,0},{supervisors,0},{workers,1}]
7> director:get_plan(foo_sup, bar_id).
{ok,[wait]}
%% I can change process plan
%% I killed process one time.
%% If i kill it again, entire supervisor will crash with reason {reached_max_restart_plan... because 'count' is 1
%% But after changing plan, its counter will restart from 0.
8> director:change_plan(foo_sup, bar_id, [restart]).
ok
9> director:get_childspec(foo_sup, bar_id).
{ok,#{append => false,count => 1,id => bar_id,
modules => [bar],
plan => [restart], %% here
start => {bar,start_link,[]},
terminate_timeout => 2000,type => worker}}
10> director:get_pids(foo_sup).
[]
11> director:restart_child(foo_sup, bar_id).
{ok,<0.111.0>}
12> {ok, Pid2} = director:get_pid(foo_sup, bar_id), erlang:exit(Pid2, kill).
true
13> director:get_pid(foo_sup, bar_id).
{ok,<0.113.0>}
14> %% Hold on
अंत में append कुंजी क्या है? वास्तव में हमेशा हमारे पास एक DefaultChildspec ।
14> director:get_default_childspec(foo_sup).
{ok,#{count => 0,modules => [],plan => [],terminate_timeout => 0}}
15>
DefaultChildspec को छोड़कर यह स्वीकार नहीं कर सकते कि सामान्य childspecs की तरह है id और append चाबियाँ।
मैं बदलते हैं तो append करने के लिए मूल्य true मेरे में Childspec :
मेरा terminate_timeout DefaultChildspec terminate_timeout में जोड़ा DefaultChildspec ।
DefaultChildspec count में मेरी count जोड़ी जाएगी।
मेरे modules DefaultChildspec modules में जोड़े जाएंगे।
DefaultChildspec plan में मेरा plan जोड़ा DefaultChildspec ।
और अगर मेरे पास है start मूल्य के साथ कुंजी {ModX, FuncX, ArgsX} में DefaultChildspec और start मूल्य के साथ कुंजी {ModY, FunY, ArgsY} में Childspec , अंतिम मूल्य हो जाएगा {ModY, FuncY, ArgsX ++ ArgsY} ।
और मैं अंत में अगर start मूल्य के साथ कुंजी {Mod, Func, Args} में DefaultChildspec , start में महत्वपूर्ण Childspec मेरे लिए वैकल्पिक है।
आप अपने खुद के DefaultChildspec को init/1 में tuple के तीसरे तत्व के रूप में वापस कर सकते हैं।
foo.erl संपादित करें:
-module(foo).
-behaviour(director). %% Yes, this is a behaviour
-export([start_link/0
,init/1]).
start_link() ->
director:start_link({local, foo_sup}, ?MODULE, null).
init(_InitArg) ->
Childspec = #{id => bar_id
,plan => [wait]
,start => {bar,start_link}
,count => 1
,terminate_timeout => 2000},
DefaultChildspec = #{start => {bar, start_link}
,terminate_timeout => 1000
,plan => [restart]
,count => 5},
{ok, [Childspec], DefaultChildspec}.
शेल को पुनरारंभ करें:
1> c(foo).
{ok,foo}
2> foo:start_link().
{ok,<0.111.0>}
3> director:get_pids(foo_sup).
[{bar_id,<0.112.0>}]
4> director:get_default_childspec(foo_sup).
{ok,#{count => 5,
plan => [restart],
start => {bar,start_link,[]},
terminate_timeout => 1000}}
5> Childspec1 = #{id => 1, append => true},
%% Default 'plan' is [Fun], so 'plan' will be [restart] ++ [Fun] or [restart, Fun].
%% Default 'count' is 1, so 'count' will be 1 + 5 or 6.
%% Args in above Childspec is [], so Args will be [] ++ [] or [].
%% Default 'terminate_timeout' is 1000, so 'terminate_timeout' will be 1000 + 1000 or 2000.
%% Default 'modules' is [bar], so 'modules' will be [bar] ++ [] or [bar].
5> director:start_child(foo_sup, Childspec1).
{ok,<0.116.0>}
%% Test
6> director:get_childspec(foo_sup, 1).
{ok,#{append => true,
count => 6,
id => 1,
modules => [bar],
plan => [restart,#Fun<director.default_plan_element_fun.2>],
start => {bar,start_link,[]},
terminate_timeout => 2000,
type => worker}}
7> director:get_pids(foo_sup).
[{bar_id,<0.112.0>},{1,<0.116.0>}]
%% I want to have 9 more children like that
8> [director:start_child(foo_sup
,#{id => Count, append => true})
|| Count <- lists:seq(2, 10)].
[{ok,<0.126.0>},
{ok,<0.127.0>},
{ok,<0.128.0>},
{ok,<0.129.0>},
{ok,<0.130.0>},
{ok,<0.131.0>},
{ok,<0.132.0>},
{ok,<0.133.0>},
{ok,<0.134.0>}]
10> director:count_children(foo_sup).
[{specs,11},{active,11},{supervisors,0},{workers,11}]
11>
आप change_default_childspec/2 का उपयोग करके change_default_childspec/2 रूप से defaultChildspec रूप से बदल सकते हैं!
और आप बच्चों के Childspec को गतिशील रूप से भी बदल सकते हैं और उनके append को true !
लेकिन कोड के विभिन्न भागों में उन्हें बदलने के साथ, आप स्पेगेटी कोड बना लेंगे
क्या मैं निर्देशक को डिबग कर सकता हूं?
Yessssss, diorector का अपना डिबग है और मानक sys:dbg_opt/0 स्वीकार करता है।
निर्देशक विभिन्न राज्यों में भी sasl और error_logger को वैध लॉग भेजता है।
1> Name = {local, dname},
Mod = foo,
InitArg = undefined,
DbgOpts = [trace],
Opts = [{debug, DbgOpts}].
[{debug,[trace]}]
2> director:start_link(Name, Mod, InitArg, Opts).
{ok,<0.106.0>}
3>
3> director:count_children(dname).
*DBG* director "dname" got request "count_children" from "<0.102.0>"
*DBG* director "dname" sent "[{specs,1},
{active,1},
{supervisors,0},
{workers,1}]" to "<0.102.0>"
[{specs,1},{active,1},{supervisors,0},{workers,1}]
4> director:change_plan(dname, bar_id, [{restart, 5000}]).
*DBG* director "dname" got request "{change_plan,bar_id,[{restart,5000}]}" from "<0.102.0>"
*DBG* director "dname" sent "ok" to "<0.102.0>"
ok
5> {ok, Pid} = director:get_pid(dname, bar_id).
*DBG* director "dname" got request "{get_pid,bar_id}" from "<0.102.0>"
*DBG* director "dname" sent "{ok,<0.107.0>}" to "<0.102.0>"
{ok,<0.107.0>}
%% Start SASL
6> application:start(sasl).
ok
... %% Log about starting SASL
7> erlang:exit(Pid, kill).
*DBG* director "dname" got exit signal for pid "<0.107.0>" with reason "killed"
true
=SUPERVISOR REPORT==== 4-May-2017::12:37:41 ===
Supervisor: dname
Context: child_terminated
Reason: killed
Offender: [{id,bar_id},
{pid,<0.107.0>},
{plan,[{restart,5000}]},
{count,1},
{count2,0},
{restart_count,0},
{mfargs,{bar,start_link,[]}},
{plan_element_index,1},
{plan_length,1},
{timer_reference,undefined},
{terminate_timeout,2000},
{extra,undefined},
{modules,[bar]},
{type,worker},
{append,false}]
8>
%% After 5000 mili-seconds
*DBG* director "dname" got timer event for child-id "bar_id" with timer reference "#Ref<0.0.1.176>"
=PROGRESS REPORT==== 4-May-2017::12:37:46 ===
supervisor: dname
started: [{id,bar_id},
{pid,<0.122.0>},
{plan,[{restart,5000}]},
{count,1},
{count2,1},
{restart_count,1},
{mfargs,{bar,start_link,[]}},
{plan_element_index,1},
{plan_length,1},
{timer_reference,#Ref<0.0.1.176>},
{terminate_timeout,2000},
{extra,undefined},
{modules,[bar]},
{type,worker},
{append,false}]
8>
एपीआई प्रलेखन उत्पन्न करें
rebar:
Pouriya@Jahanbakhsh ~/director $ rebar doc
rebar3:
Pouriya@Jahanbakhsh ~/director $ rebar3 edoc
erl
Pouriya@Jahanbakhsh ~/director $ mkdir -p doc &&
erl -noshell\
-eval "edoc:file(\"./src/director.erl\", [{dir, \"./doc\"}]),init:stop()."
उपरोक्त आदेशों में से एक को चलाने के बाद, HTML दस्तावेज़ीकरण doc निर्देशिका में होना चाहिए।