Supervisor Behaviour是一個用來實現一個supervisor進程來監控其餘子進程的模塊 子進程能夠是另外一個supervisor,也能夠是一個worker進程. worker進程通常使用gen_event,gen_fsm或gen_server behaviour來實現. 一個使用該模塊來實現的supervisor有一個接口方法的標準集,包括跟蹤和錯誤報告的功能. supervisor用來構建一個分層進程結構,稱爲supervision tree,這是組織一個容錯系統的好方式 1,Supervision原則 supervisor負責啓動、中止和監控它的子進程 supervisor在必要時經過重啓它的子進程來保持它們活着 supervisor的子被定義爲一個子規範的list 當supervisor啓動時,子進程按list從左至右的順序啓動 當supervisor終止時,它首先按啓動順序的反順序終止它的子進程 2,例子 啓動服務器的supervisor的callback模塊: -module(ch_sup). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link(ch_sup, []). init(_Args) -> {ok, {{one_for_one, 1, 60}, [{ch3, {ch3, start_link, []}, permanent, brutal_kill, worker, [ch3]}]}}. one_for_one是重啓策略之一 1和60定義了最大重啓頻率 tuple {ch3, …}是子規範 3,重啓策略 3.1 one_for_one 若是一個子進程中止,則只重啓該進程 3.2 one_for_all 若是一個子進程中止,全部其餘子進程也中止,而後全部進程重啓 3.3 rest_for_one 若是一個子進程中止,則啓動順序中在它以後的全部其餘子進程也中止,而後中止的這些進程重啓(跟樓上那位不同) 3.4 simple_one_for_one 一個簡化的one_for_one supervisor,全部的子進程都是一樣進程類型而且是動態添加的實例 4,最大重啓頻率 supervisor有一個自帶的機制來限制給定時間內重啓的次數 這是經過MaxR和MaxT這兩個參數來決定的 init(...) -> {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec, ...]}}. 若是在最近的MaxT秒以內有超過MaxR次數的重啓,則supervisor中止它自己和它全部的子進程 當supervisor中止後,下一個更高級別的supervisor進行下一步動做,重啓該中止的supervisor或者終止自己 重啓機制的意圖是防止一個進程因爲某些緣由重複性的死掉 5,子規範 這是子規範的類型定義: Module = atom() {Id, StartFunc, Restart, Shutdown, Type, Modules} Id = term() StartFunc = {M, F, A} M = F = atom() A = [term()] Restart = permanent | transient | temporary Shutdown = brutal_kill | integer() >=0 | infinity Type = worker | supervisor Modules = [Module] | dynamic Module = atom() Id是用來讓supervisor內部識別子規範的名字 StartFunc定義了用來啓動子進程的的方法,符合module-function-arguments tuple{M, F, A} 它應該調用supervisor:start_link,gen_server:start_link,gen_fsm:start_link或gen_event:start_link,或相適應的方法 Restart定義了子進程何時重啓 1)permanent表示子進程始終重啓 2)temporary表示子進程決不重啓 3)transient表示只有在子進程異常終止時才重啓,即除了normal之外的終止緣由 Shutdown定義了子進程怎樣終止 1)brutal_kill表示子進程使用exit(Child, kill)來無條件的終止 2)一個整數timeout值表示supervisor告訴子進程經過調用exit(Child, shutdown)來終止,而後等待一個exit信號返回 若是沒有在指定的時間內接收到exit信號,則子進程使用exit(Child, kill)來無條件的終止 3)若是子進程是另外一個supervisor,它應該設置爲infinity來給子樹足夠的時間來終止 Type指定子進程是一個supervisor仍是一個worker Modules應該是一個list,含有一個元素[Module] 若是子進程是一個supervisor,gen_server或gen_fsm則Module是callback模塊的名字 若是子進程是一個gen_event,則Modules應該爲dynamic 該信息用來在升級和降級時供release handler使用 例子:啓動服務器ch3的子規範 {ch3, {ch3, start_link, []}, permanent, brutal_kill, worker, [ch3]} 例子:啓動event manager的子規範 {error_man, {gen_event, start_link, [{local, error_man}]}, permanent, 5000, worker, dynamic} 服務器和event manager都是註冊進程,能夠在任什麼時候候訪問,這樣它們都指定爲permanent ch3不須要在終止以前作任何清理工做,這樣就不須要timeout,可是必須知足brutal_kill,error_man可能須要一些時間來讓event handler清理,這樣Shutdown設置爲5000ms 例子:啓動另外一個supervisor的子規範 {sup, {sup, start_link, []}, transient, infinity, supervisor, [sup]} 6,啓動一個supervisor 上面的例子經過調用ch_sup:start_link()來啓動supervisor: start_link() -> supervisor:start_link(ch_sup, []). ch_sup:start_link調用方法supervisor:start_link/2,這個方法啓動一個新的supervisor進程並鏈接它 1)第一個參數ch_sup是callback模塊的名字,它是init callback方法所在的位置 2)第二個參數[]是傳給init callback方法的參數 一個supervisor進程調用callback方法ch_sup:init([]),返回{ok, StateSpec}: init(_Args) -> {ok, {{one_for_one, 1, 60}, [{ch3, {ch3, start_link, []}, permanent, brutal_kill, worker, [ch3]}]}}. 而後根據指定的子規範的入口來啓動它的全部子進程,在這裏有一個子進程ch3 注意supervisor:start_link是同步帶,看成有子進程啓動以後纔會返回 7,添加一個子進程 除了靜態的supervision tree,咱們也能夠添加動態子進程到已有的supervisor裏: supervisor:start_child(Sup, ChildSpec) Sup是supervisor的pid或名字,ChildSpec是子規範 使用start_child/2來添加的子進程表現出像其餘子進程同樣的行爲,除了這點:若是supervisor死掉而後重啓,則全部動態添加的子進程都將丟失 8,中止一個子進程 任何子進程,無論靜態的仍是動態的,均可以使用shutdown規範來中止: supervisor:terminate_child(Sup, Id) 中止的子進程的子規範使用以下調用來刪除: supervisor:delete_child(Sup, Id) Sup是supervisor的pid或name,Id是子規範裏指定的id 就像動態添加的子進程同樣,若是supervisor自己重啓,那麼刪除靜態子進程的效果會丟失 9,simple_one_for_one supervisor simple_one_for_one重啓策略的supervisor是一個簡化的one_for_one supervisor,全部的子進程都是動態添加的同一進程的實例 一個simple_one_for_one supervisor callback模塊的例子: -module(simple_sup). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link(simple_sup, []). init(_Args) -> {ok, {{simple_one_for_one, 0, 1}, [{call, {call, start_link, []}, temporary, brutal_kill, worker, [call]}]}}. -module(simple_sup). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link(simple_sup, []). init(_Args) -> {ok, {{simple_one_for_one, 0, 1}, [{call, {call, start_link, []}, temporary, brutal_kill, worker, [call]}]}}. 當啓動後,supervisor將不會啓動任何子進程,而是經過調用以下代碼來動態添加全部的子進程: supervisor:start_child(Sup, List) Sup是supervisor的pid或name,List是一個任意的term列表,將會被動態添加到子規範的參數列表裏 若是啓動方法指定爲{M, F, A},則子進程經過調用apply(M, F, A++List)來啓動 例如,添加一個子進程到simple_sup: supervisor:start_child(Pid, [id1]) 這將會經過調用apply(call, start_link, []++[id1])即call:start_link(id1)來啓動子進程 10,終止 既然supervisor是supervision tree的一部分,則它將自動被它的supervisor終止 當終止時,它會按啓動的反順序根據相應的shudown規範來自動終止它全部的子進程,而後終止自己 補充:supervisor exports and callbacks supervisor module Callback module supervisor:start_link Module:init/1 supervisor:start_child supervisor:terminate_child supervisor:delete_child supervisor:restart_child supervisor:which_children supervisor:check_childspecs