概要:
通用監督者行爲
描述:
一個實現監督者的行爲模塊,一個監督被稱爲子進程的其它進程的進程。一個子進程能夠是另外一個監督者或工做者進程。工做者進程一般的實現使用gen_event,gen_fsm和gen_server中的行爲。監督者使用這個模塊實現一組標準的接口函數和包括跟蹤和錯誤報告的功能。監督者被用來構建稱爲監控樹的分層進程結構,一個構建容錯應用的很好的方式。參考OTP設計原理得到更多信息。
監督者設定哪些子進程被監督的定義,位於導出一組預約義函數的回調模塊。
除非另做說明,若是指定的supervisor不存在或給出錯誤參數,該模塊全部函數會失敗。
監督原則:
監督者負責啓動、中止和監控它的子進程。監督者的基本思想是,它應該保證它的子進程活着,必要時重啓它們。
監督者的子進程被定義爲子規範列表。當監督者被啓動時,子進程依據這個列表從左到右按順序被啓動。當監督者終止時,它首先按相反的啓動順序,從右到左終止它的子進程。
監督者能夠有如下重啓策略之一:
one_for_one - 若是子進程終止,應從新啓動,只有子進程受到影響。
one_for_all - 若是子進程終止,應從新啓動,全部其它子進程終止,那麼全部的子進程被啓動。
rest_for_one - 若是子進程終止,應從新啓動,後面的子進程,也就是說,按啓動順序,被終止進程的後面的子進程被終止。那麼,終止進程和它後面全部的子進程被重啓。
simple_one_for_one - 簡化的one_for_one監督者,其中,全部的子進程被動態添加一樣進程類型的實例,也就是,運行相同的代碼。
對於simple_one_for_one監督者,函數delete_child/2 和 restart_child/2是有效的。若是指定的監督者使用該重啓策略,會返回{error,simple_one_for_one}。
在simple_one_for_one監督者下,經過給定子進程的進程號做爲第二個參數,函數terminate_child/2可被用於子進程。若是子規範標識符被使用,terminate_child/2將返回{error,simple_one_for_one}。
由於一個simple_one_for_one監督者能夠有不少的子進程,它在同一時間將它們關閉。因此,它們被中止的順序沒有被定義。出於一樣的緣由,它可能有一個開銷對於關閉策略。
爲防止監督者進入子進程終止和重啓的無限循環,使用兩個整數MaxR 和 MaxT定義最大重啓頻率。若是在MaxT秒重啓超過MaxR發生,監督者終止全部子進程,隨後終止它本身。
這是子規範的類型定義:
child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
Id = term()
StartFunc = {M,F,A}
M = F = atom()
A = [term()]
Restart = permanent | transient | temporary
Shutdown = brutal_kill | int()>0 | infinity
Type = worker | supervisor
Modules = [Module] | dynamic
Module = atom()
Id是一個名稱,在內部被監督者用於標識子規範。
StartFunc定義函數調用用於啓動子進程。它應該是一個模塊-函數-參數元組{M,F,A}用做apply(M,F,A)。
啓動函數必須建立和連接到子進程,應該返回{ok,Child}或{ok,Child,Info},其中Child是子進程的進程號,Info是任意term被監督者忽略。
若是子進程由於一些緣由不能啓動,啓動函數也能夠返回ignore,這種狀況,子規範將會被監督者保存(除非它是temporary進程),但不存在的子進程將被忽略。
若是出現錯誤,函數也可能返回錯誤元組{error,Error}。
請注意,start_link函數,不一樣的行爲模塊知足上述的要求。
Restart定義何時終止的子進程應該被重啓。一個permanent子進程應該老是被重啓,一個temporary子進程從不被重啓(即便當監督者的重啓策略是rest_for_one或one_for_all和兄弟進程的掛掉致使temporary進程被終止),和一個transient子進程應該被重啓僅當它異常終止,也就是說,除過normal,shutdown或{shutdown,Term}的其它退出緣由。
Shutdown定義子進程應該如何被終止。brutal_kill意味着子進程將被無條件終止使用exit(Child,kill)。一個整數超時值意味着監督者將告訴子進程經過調用exit(Child,shutdown)來終止,而後以緣由shutdown等待來自子進程的退出信號。若是在指定數目毫秒內沒有收到退出信號,子進程使用exit(Child,kill)被無條件終止。
若是子進程是另外一個監督者,Shutdown應該被設置成infinity,給子樹充足的時間關閉。若是子進程是工做者,它也被容許設置成infinity。
警告:當心設置shutdown策略爲infinity,當子進程是一個工做者。由於,在這種情形下,監控樹的終止取決於子進程,它必須以安全的方式實現,它的清理過程必須返回。
請注意,全部子進程自動使用標準OTP行爲模塊實現依據關閉協議。
Type指定子進程是監督者仍是工做者。
Modules被版本處理程序使用,在代碼替換期間用於肯定哪些進程使用哪些模塊。做爲一個經驗法則,Modules應該一個元素列表[Module],其中,Module是回調模塊,若是子進程是一個supervisor, gen_server 或 gen_fsm。若是子進程是一個帶有回調模塊集合的事件管理器(gen_event),Modules應該是dynamic。關於版本控制的更多信息參考OTP設計原則。
內部地,監督者也跟蹤子進程的進程號,或undefined若是沒有進程號存在。
數據類型:
child() = undefined | pid()
child_id() = term() %% 不是pid()
child_spec() =
{Id :: child_id(),
StartFunc :: mfargs(),
Restart :: restart(),
Shutdown :: shutdown(),
Type :: worker(),
Modules :: modules()}
mfargs() = {M :: module(), F :: atom(), A :: [term()] | undefined} %% 若是Restart是temporary,A的值爲undefined。
modules() = [module()] | dynamic
restart() = permanent | transient | temporary
shutdown() = brutal_kill | timeout()
strategy() = one_for_all | one_for_one | rest_for_one | simple_one_for_one
sup_ref() = (Name :: atom())
| {Name :: atom(), Node :: node()}
| {global, Name :: atom()}
| {via, Module :: module(), Name :: any()}
| pid()
worker() = worker | supervisor
導出:
start_link(Module, Args) -> startlink_ret()
start_link(SupName, Module, Args) -> startlink_ret()
Types:
SupName = sup_name()
Module = module()
Args = term()
startlink_ret() = {ok, pid()} | ignore | {error, startlink_err()}
startlink_err() = {already_started, pid()} | {shutdown, term()} | term()
sup_name() = {local, Name :: atom()} | {global, Name :: atom()} | {via, Module :: module(), Name :: any()}
建立一個監督者進程做爲監控樹的一部分,在其它方面,函數將確保監督者連接到調用者進程(它的監督者)。node
被建立的監督者進程調用Module:init/1找出重啓策略、最大啓動頻率和子進程。爲確保同步啓動過程,start_link/2,3不會返回直到Module:init/1已經返回且全部子進程已被啓動。
若是SupName={local,Name},supervisor使用register/2被註冊爲本地的Name。若是SupName={global,Name},supervisor使用global:register_name/2被註冊爲全局的Name。若是沒有提供Name,supervisor不會被註冊。若是SupName={via,Module,ViaName},supervisor將會用Module表明的註冊表註冊。Module回調應該導出函數register_name/2, unregister_name/1, whereis_name/1 和 send/2,它們表現得像global模塊對應的函數。所以,{via,global,Name}是一個有效地引用。
若是沒有提供名稱,監督者不會註冊。
Module是回調模塊的名稱。
Args是一個任意term,做爲參數傳遞給Module:init/1。
若是監督者和它的子進程被成功建立,(也就是說,若是全部子進程啓動函數返回{ok,Child}, {ok,Child,Info}, 或 ignore)函數返回{ok,Pid},其中Pid是監督者的進程號。若是已存在指定SupName的進程,函數返回{error,{already_started,Pid}},其中,Pid是那個進程的進程號。
若是Module:init/1返回ignore,該函數也返回ignore,而監督者以緣由normal終止。若是Module:init/1失敗或返回不正確的值,該函數返回{error,Term},其中,Term是包含關於錯誤信息的Term,監督者以緣由Term終止。
若是任何子進程啓動函數是失敗或返回一個錯誤元組或一個錯誤值,監督者首先將以緣由shutdown終止全部已啓動的進程,隨後終止它本身,而後返回{error, {shutdown, Reason}}。
start_child(SupRef, ChildSpec) -> startchild_ret()
Types:
SupRef = sup_ref()
ChildSpec = child_spec() | (List :: [term()])
child_spec() =
{Id :: child_id(),
StartFunc :: mfargs(),
Restart :: restart(),
Shutdown :: shutdown(),
Type :: worker(),
Modules :: modules()}
startchild_ret() = {ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, startchild_err()}
startchild_err() = already_present | {already_started, Child :: child()} | term()
動態增長一個子規範到監督者SuperRef,它啓動對應的子進程。安全
ServerRef能夠是:
- 進程號;
- Name,supervisor被本地註冊的名稱;
- {Name,Node},supervisor在其它節點被本地註冊;
- {global,Name},supervisor被全局註冊;
- {via,Module,ViaName},supervisor經過替代的進程註冊表註冊。
ChildSpec應該是有效的子進程(除非該監督者是一個simple_one_for_one的監督者,看下面)。子進程將會使用定義在子規範的啓動函數啓動。
若是是simple_one_for_one監督者的狀況下,定義在Module:init/1的子規範將被使用,ChildSpec應該是一個任意term列表。子進程將被啓動經過添加List到已存在的啓動函數參數,也就是說,經過調用apply(M, F, A++List),其中,{M,F,A}是定義在子規範的啓動函數。
若是已經存在一個指定id的子規範,ChildSpec被丟棄,函數返回{error,already_present} 或 {error,{already_started,Child}},取決於對應的子進程是否運行。
若是子進程啓動函數返回{ok,Child} 或 {ok,Child,Info},子規範和進程號被添加到監督者,函數返回相同的值。
若是子進程啓動函數返回ignore,子規範被添加到監督者,進程號設置爲undefined,函數返回{ok,undefined}。
若是子進程啓動哈數返回一個錯誤元組或一個錯誤值, 或它失敗,子規範被丟棄,函數返回{error,Error},其中Error是一個包含關於錯誤和子規範信息的term。
terminate_child(SupRef, Id) -> Result
Types:
SupRef = sup_ref()
Id = pid() | child_id()
Result = ok | {error, Error}
Error = not_found | simple_one_for_one
告訴監督者SupRef終止給定的子進程。
若是監督者不是simple_one_for_one,Id必須是子規範標識符。進程被終止,若是有,除非它是temporary子進程,子規範被監督者保存。子進程隨後可能被監督者重啓。子進程也可能顯式的經過調用restart_child/2被重啓。使用delete_child/2移除子規範。
若是子進程是temporary,進程一終止,子規範就被刪除。這意味着delete_child/2沒有意義,restart_child/2沒法用於這些進程。
若是監督者是simple_one_for_one,Id必須是子進程的pid(),若是指定的進程活着,但不是給定監督者的子進程,函數將返回{error,not_found}。若是給定子規範標識,而不是pid(),函數將返回{error,simple_one_for_one}。
若是成功,函數返回ok。若是沒有指定Id的子規範,函數返回{error,not_found}。
參考start_child/2瞭解SupRef的描述。
restart_child(SupRef, Id) -> Result
Types:
SupRef = sup_ref()
Id = child_id()
Result = {ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, Error}
Error = running | restarting | not_found | simple_one_for_one | term()
告訴監督者SupRef重啓一個子進程根據子規範標識符Id。子規範必須存在,對應子進程必須沒有在運行。app
請注意temporary子進程,當子進程終止,子規範自動被刪除。隨後,它不能重啓這些子進程。
參看start_child/2瞭解SupRef的描述。
若是子規範標識Id不存在,函數返回{error,not_found}。若是子規範存在但對應進程已經運行,函數返回{error,running}。
子進程啓動函數返回{ok,Child} 或 {ok,Child,Info},進程號被添加到監督者,函數返回相同的值。
子進程啓動函數返回ignore,進程號仍然設置爲undefined,函數返回{ok,undefined}。
子進程啓動函數返回一個錯誤元組或一個錯誤值,或它失敗,函數返回{error,Error},其中,Error是一個包含錯誤信息的term。
which_children(SupRef) -> [{Id, Child, Type, Modules}]
Types:
SupRef = sup_ref()
Id = child_id() | undefined
Child = child() | restarting
Type = worker()
Modules = modules()
返回一個新建立列表,含有全部子規範和歸屬於監督者SupRef的子進程。函數
請注意,在低內存狀態下,監督大量子進程,調用該函數可能致使內存不足的異常。
參考start_child/2瞭解SupRef的描述。
對於每一個子規範/進程給出的信息是:
- Id - 子規範中定義或在simple_one_for_one監督者狀況下爲undefined;
- Child - 對應子進程的進程號,函數將被重啓爲restarting或沒有該進程爲undefined;
- Type - 定義在子規範;
- Modules - 定義在子規範。
count_children(SupRef) -> PropListOfCounts
Types:
SupRef = sup_ref()
PropListOfCounts = [Count]
Count = {specs, ChildSpecCount :: integer() >= 0} | {active, ActiveProcessCount :: integer() >= 0}
| {supervisors, ChildSupervisorCount :: integer() >= 0} | {workers, ChildWorkerCount :: integer() >= 0}
返回一個屬性列表,它包含監督者子規範的下列元素和被管理的進程的數量:
- specs - 子進程活的或死的總數量;
- active - 全部被監督者管理的激活的運行的子進程數量;
- supervisors - 在規範列表被標記爲child_type = supervisor的全部子進程數量,無論子進程是否活着;
- workers - 在規範列表被標記爲child_type = worker的全部子進程數量,無論子進程是否活着;
check_childspecs(ChildSpecs) -> Result
Types:
ChildSpecs = [child_spec()]
Result = ok | {error, Error :: term()}
該函數須要一個子規範列表做爲參數,若是他們在語法上都正確,返回ok,不然返回{error,Error}。atom
回調函數:
Module:init(Args) -> Result
Types:
Args = term()
Result = {ok,{{RestartStrategy,MaxR,MaxT},[ChildSpec]}} | ignore
RestartStrategy = strategy()
MaxR = integer()>=0
MaxT = integer()>0
ChildSpec = child_spec()
不管什麼時候使用supervisor:start_link/2,3 監督者被啓動,函數被一個新的進程調用找出重啓策略、最大重啓頻率和子規範。spa
Args是提供給啓動函數的參數。
RestartStrategy是重啓策略,MaxR 和 MaxT定義監督者的最大重啓頻率。 [ChildSpec]是一組有效地子規範,它定義哪些進程監督者應該啓動和監控。參看上面關於監督原則的討論。
請注意,當重啓策略爲simple_one_for_one,子規範列表必須只含有一個子規範列表(ID被忽略)。在初始化期間,沒有子進程隨後被啓動,可是全部子進程被設定使用supervisor:start_child/2來動態啓動。
函數也可能返回ignore。