檢視原始碼 Supervisor 行為 (Elixir v1.16.2)
用於實作監督器的行為模組。
監督器是一個處理其他處理程序的處理程序,我們稱之為子處理程序。監督器用於建立稱為監督樹的階層式處理程序結構。監督樹提供容錯能力,並封裝我們的應用程式如何啟動和關閉。
監督器可以使用子規格清單透過 start_link/2
直接啟動,或者您可以定義實作所需回呼的基於模組的監督器。以下各節在大部分範例中使用 start_link/2
啟動監督器,但它也包含一個關於基於模組的監督器的特定章節。
範例
為了啟動監督器,我們需要先定義一個將被監督的子處理程序。舉例來說,我們將定義一個 GenServer
,一個通用伺服器,用於保留計數器。其他處理程序接著可以將訊息傳送給這個處理程序,以讀取計數器並增加其值。
免責聲明
實際上,您不會將計數器定義為 GenServer。相反地,如果您需要一個計數器,您會將它作為輸入和輸出傳遞給需要它的函式。我們在這個範例中選擇計數器是因為它很簡單,因為它讓我們可以專注在監督器如何運作。
defmodule Counter do
use GenServer
def start_link(arg) when is_integer(arg) do
GenServer.start_link(__MODULE__, arg, name: __MODULE__)
end
## Callbacks
@impl true
def init(counter) do
{:ok, counter}
end
@impl true
def handle_call(:get, _from, counter) do
{:reply, counter, counter}
end
def handle_call({:bump, value}, _from, counter) do
{:reply, counter, counter + value}
end
end
Counter
在 start_link
上接收一個參數。這個參數傳遞給 init/1
回呼,而這個回呼會變成計數器的初始值。我們的計數器處理兩個操作(稱為呼叫): :get
,用於取得目前的計數器值,和 :bump
,它會將計數器增加指定的 value
,並傳回舊計數器。
我們現在可以啟動一個監督器,它將啟動並監督我們的計數器處理程序。第一步是定義控制每個子行為的子規格清單。每個子規格都是一個映射,如下所示
children = [
# The Counter is a child started via Counter.start_link(0)
%{
id: Counter,
start: {Counter, :start_link, [0]}
}
]
# Now we start the supervisor with the children and a strategy
{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
# After started, we can query the supervisor for information
Supervisor.count_children(pid)
#=> %{active: 1, specs: 1, supervisors: 0, workers: 1}
請注意,在啟動 GenServer 時,我們透過 name: __MODULE__
選項將它註冊為名稱 Counter
。這讓我們可以直接呼叫它並取得它的值
GenServer.call(Counter, :get)
#=> 0
GenServer.call(Counter, {:bump, 3})
#=> 0
GenServer.call(Counter, :get)
#=> 3
不過,我們的計數器伺服器有一個錯誤。如果我們使用非數字值呼叫 :bump
,它就會崩潰
GenServer.call(Counter, {:bump, "oops"})
** (exit) exited in: GenServer.call(Counter, {:bump, "oops"}, 5000)
幸運的是,由於伺服器是由一個監督程式監督,因此監督程式會自動啟動一個新的伺服器,並將其重置回 0
的初始值
GenServer.call(Counter, :get)
#=> 0
監督程式支援不同的策略;在上面的範例中,我們選擇了 :one_for_one
。此外,每個監督程式可以有多個工作人員和/或監督程式作為子項,每個子項都有自己的設定(如「子項規範」部分所述)。
本文檔的其餘部分將介紹如何指定子程序,如何啟動和停止它們,不同的監督策略等等。
子項規範
子項規範描述了監督程式如何啟動、關閉和重新啟動子程序。
子項規範是一個包含最多 6 個元素的映射。以下清單中的前兩個鍵是必需的,其餘的鍵是可選的
:id
- 監督程式內部用於識別子項規範的任何術語;預設為給定的模組。此鍵是必需的。對於監督程式,如果:id
值衝突,監督程式將拒絕初始化並需要明確的 ID。不過,對於 動態監督程式 來說並非如此。:start
- 一個包含模組-函式-引數的元組,用於呼叫以啟動子程序。此鍵是必需的。:restart
- 一個原子,定義何時應重新啟動已終止的子程序(請參閱下方的「重新啟動值」部分)。此鍵是可選的,預設為:permanent
。:shutdown
- 一個整數或原子,定義如何終止子程序(請參閱下方的「關閉值」部分)。此鍵是可選的,如果類型為:worker
,預設為5_000
;如果類型為:supervisor
,預設為:infinity
。:type
- 指定子程序是:worker
還是:supervisor
。此鍵是可選的,預設為:worker
。:modules
- 熱程式碼升級機制用於確定哪些程序正在使用特定模組的模組清單。它通常設定為GenServer
、Supervisor
等行為的回呼模組。它會根據:start
值自動設定,而且在實務上很少變更。:significant
- 一個布林值,表示是否應將子程序視為與自動關閉相關的重要程序。只有:transient
和:temporary
子程序可以標記為重要。此鍵是可選的,預設為false
。有關更多詳細資訊,請參閱下方的「自動關閉」部分。
讓我們了解 :shutdown
和 :restart
選項控制什麼。
關閉值 (:shutdown)
下列關閉值在 :shutdown
選項中受支援
:brutal_kill
- 子程序會使用Process.exit(child, :kill)
立即且無條件地終止。任何整數 >= 0 - 主管程式在發出
Process.exit(child, :shutdown)
訊號後,會等待子程序終止的毫秒數。如果子程序未捕捉退出,則初始:shutdown
訊號會立即終止子程序。如果子程序捕捉退出,則它有指定的時間來終止。如果它未在指定時間內終止,則子程序會透過Process.exit(child, :kill)
無條件地由主管程式終止。:infinity
- 作為整數運作,但主管程式會無限期地等待子程序終止。如果子程序是主管程式,建議值為:infinity
,以給予主管程式及其子程序足夠的時間關閉。此選項可用於一般工作者,但並不建議使用,且需要極度小心。如果未小心使用,子程序將永遠不會終止,也會阻止您的應用程式終止。
重新啟動值 (:restart)
:restart
選項控制主管程式應將什麼視為成功終止或不成功終止。如果終止成功,主管程式不會重新啟動子程序。如果子程序崩潰,主管程式會啟動新的子程序。
下列重新啟動值在 :restart
選項中受支援
:permanent
- 子程序總是重新啟動。:temporary
- 子程序永遠不會重新啟動,無論監督策略為何:任何終止(即使異常)都視為成功。:transient
- 子程序僅在異常終止時重新啟動,即,退出原因不為:normal
、:shutdown
或{:shutdown, term}
。
如需更完整地了解退出原因及其影響,請參閱「退出原因和重新啟動」部分。
child_spec/1
函數
啟動監督程序時,我們可以傳遞一個子規格清單。這些規格是告訴監督程序如何啟動、停止和重新啟動每個子程序的映射
%{
id: Counter,
start: {Counter, :start_link, [0]}
}
上面的映射定義了一個子程序,其 :id
為 Counter
,通過呼叫 Counter.start_link(0)
啟動。
但是,將每個子程序的子規格定義為映射可能會很容易出錯,因為我們可能會更改 Counter
實作而忘記更新其規格。這就是 Elixir 允許您傳遞包含模組名稱和 start_link
參數的元組,而不是規格
children = [
{Counter, 0}
]
然後監督程序將呼叫 Counter.child_spec(0)
來擷取子規格。現在 Counter
模組負責建立自己的規格,例如,我們可以寫
def child_spec(arg) do
%{
id: Counter,
start: {Counter, :start_link, [arg]}
}
end
然後監督程序將呼叫 Counter.start_link(arg)
來啟動子程序。此流程總結在下面的圖表中。呼叫者是一個產生監督程序程序的程序。然後監督程序繼續呼叫您的程式碼 (模組) 來產生其子程序
sequenceDiagram
participant C as Caller (Process)
participant S as Supervisor (Process)
participant M as Module (Code)
note right of C: child is a {module, arg} specification
C->>+S: Supervisor.start_link([child])
S-->>+M: module.child_spec(arg)
M-->>-S: %{id: term, start: {module, :start_link, [arg]}}
S-->>+M: module.start_link(arg)
M->>M: Spawns child process (child_pid)
M-->>-S: {:ok, child_pid} | :ignore | {:error, reason}
S->>-C: {:ok, supervisor_pid} | {:error, reason}
對我們來說幸運的是,use GenServer
已經定義了一個 Counter.child_spec/1
,就像上面一樣,所以您不需要自己撰寫上面的定義。如果您想要自訂自動產生的 child_spec/1
函數,您可以將選項直接傳遞給 use GenServer
use GenServer, restart: :transient
最後,請注意,也可以簡單地將 Counter
模組傳遞為子程序
children = [
Counter
]
當只給出模組名稱時,它等於 {Counter, []}
,在我們的案例中這將是無效的,這就是為什麼我們總是明確傳遞初始計數器的原因。
通過將子規格替換為 {Counter, 0}
,我們將其封裝在 Counter
模組中。我們現在可以與其他開發人員分享我們的 Counter
實作,他們可以將其直接新增到他們的監督樹中,而不用擔心計數器的底層細節。
總體而言,子規格可以是下列其中之一
表示子規格本身的映射 - 如「子規格」部分所述
一個元組,其第一個元素為模組,第二個元素為啟動參數 - 例如
{Counter, 0}
。在此情況下,呼叫Counter.child_spec(0)
來擷取子規格一個模組 - 例如
Counter
。在此情況下,將呼叫Counter.child_spec([])
,這對於計數器來說是無效的,但在許多其他情況下很有用,特別是當您想要將選項清單傳遞給子程序時
如果您需要將 {module, arg}
元組或模組子規格轉換為 子規格 或修改子規格本身,您可以使用 Supervisor.child_spec/2
函數。例如,要以不同的 :id
和 10 秒(10_000 毫秒)的 :shutdown
值執行計數器
children = [
Supervisor.child_spec({Counter, 0}, id: MyCounter, shutdown: 10_000)
]
監督策略和選項
到目前為止,我們已經啟動了監督,將單個子項作為元組傳遞,以及稱為 :one_for_one
的策略
children = [
{Counter, 0}
]
Supervisor.start_link(children, strategy: :one_for_one)
傳遞給 start_link/2
的第一個參數是子規格清單,如上方的「child_spec/1」區段所定義。
第二個參數是選項關鍵字清單
:strategy
- 監督策略選項。它可以是:one_for_one
、:rest_for_one
或:one_for_all
。必填。請參閱「策略」區段。:max_restarts
- 在時間範圍內允許的最大重新啟動次數。預設為3
。:max_seconds
-:max_restarts
適用的時間範圍。預設為5
。:auto_shutdown
- 自動關閉選項。它可以是:never
、:any_significant
或:all_significant
。選填。請參閱「自動關閉」區段。:name
- 註冊監督程序的名稱。支援的值說明於GenServer
文件中的「名稱註冊」區段。選填。
策略
監督支援不同的監督策略(透過上述所見的 :strategy
選項)
:one_for_one
- 如果子程序終止,只會重新啟動該程序。:one_for_all
- 如果子程序終止,所有其他子程序都會終止,然後重新啟動所有子程序(包括已終止的子程序)。:rest_for_one
- 如果子程序終止,會終止已終止的子程序,以及之後啟動的其他子程序,然後重新啟動。
在上述情況中,程序終止是指不成功的終止,由 :restart
選項決定。
若要有效地監督動態啟動的子程序,請參閱 DynamicSupervisor
。
自動關閉
當標記為 :significant
的子程序退出時,監督有能力自動關閉自己。
監控器支援不同的自動關閉選項(透過上述看到的 :auto_shutdown
選項)
:never
- 這是預設值,自動關閉已停用。:any_significant
- 如果任何重要的子程序退出,監控器會自動關閉其子程序,然後關閉它自己。:all_significant
- 當所有重要的子程序退出時,監控器會自動關閉其子程序,然後關閉它自己。
只有 :transient
和 :temporary
子程序可以標記為重要的,而且此組態會影響行為。重要的 :transient
子程序必須正常退出才能考慮自動關閉,而 :temporary
子程序可能會因為任何原因而退出。
名稱註冊
監控器與 GenServer
繫結到相同的名稱註冊規則。在 GenServer
的文件當中進一步了解這些規則。
基於模組的監控器
在目前的範例中,監控器是透過將監控結構傳遞給 start_link/2
來啟動的。然而,監控器也可以透過明確定義監控模組來建立
defmodule MyApp.Supervisor do
# Automatically defines child_spec/1
use Supervisor
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@impl true
def init(_init_arg) do
children = [
{Counter, 0}
]
Supervisor.init(children, strategy: :one_for_one)
end
end
這兩種方法的差異在於,基於模組的監控器提供您更直接的控制權,以控制監控器如何初始化。我們不必呼叫 Supervisor.start_link/2
,並提供一個子規格清單,而這些子規格會隱含地為我們初始化,我們必須明確地呼叫 Supervisor.init/2
,並在 init/1
回呼中初始化子程序。 Supervisor.init/2
接受與 start_link/2
相同的 :strategy
、:max_restarts
和 :max_seconds
選項。
使用 Supervisor
當您
use Supervisor
時,Supervisor
模組會設定@behaviour Supervisor
並定義一個child_spec/1
函式,因此您的模組可以用作監控樹中的子程序。
use Supervisor
也定義了 child_spec/1
函數,它允許我們將 MyApp.Supervisor
作為另一個監督者的子項或作為監督樹的頂部執行,如下所示
children = [
MyApp.Supervisor
]
Supervisor.start_link(children, strategy: :one_for_one)
一般準則是在監督樹的頂部使用沒有回呼模組的監督者,通常在 Application.start/2
回呼中。我們建議對應用程式中的任何其他監督者使用基於模組的監督者,以便它們可以在樹中作為另一個監督者的子項執行。由 Supervisor
自動產生的 child_spec/1
可以使用下列選項自訂
:id
- 子項規格識別碼,預設為目前的模組:restart
- 監督者應該重新啟動的時間,預設為:permanent
緊接在 use Supervisor
之前的 @doc
註解會附加到產生的 child_spec/1
函數。
啟動和關閉
當監督者啟動時,它會遍歷所有子項規格,然後按定義順序啟動每個子項。這是透過呼叫子項規格中 :start
鍵下定義的函數來完成,通常預設為 start_link/1
。
然後會為每個子程序呼叫 start_link/1
(或自訂函數)。start_link/1
函數必須傳回 {:ok, pid}
,其中 pid
是連結到監督者的新程序的程序識別碼。子程序通常會透過執行 init/1
回呼來開始其工作。一般來說,init
回呼是我們初始化和設定子程序的地方。
關閉程序會以相反順序進行。
當監督程序關閉時,它會以與列出順序相反的順序終止所有子程序。終止會透過 Process.exit(child_pid, :shutdown)
將關閉退出訊號傳送至子程序,然後等待一段時間讓子程序終止。此間隔預設為 5000 毫秒。如果子程序在此間隔內未終止,監督程序會以理由 :kill
突然終止子程序。關閉時間可以在子程序規格中設定,下一節將詳細說明。
如果子程序未捕捉退出,則在收到第一個退出訊號時會立即關閉。如果子程序正在捕捉退出,則會呼叫 terminate
回呼,而子程序必須在合理的時間間隔內終止,否則會被監督程序突然終止。
換句話說,如果在應用程式或監督樹狀結構關閉時,某個程序清理自身很重要,則此程序必須捕捉退出,其子程序規格應指定適當的 :shutdown
值,確保它在合理的時間間隔內終止。
退出理由和重新啟動
監督程序會根據其 :restart
設定重新啟動子程序。例如,當 :restart
設為 :transient
時,如果子程序以理由 :normal
、:shutdown
或 {:shutdown, term}
退出,監督程序不會重新啟動子程序。
這些退出也會影響記錄。預設情況下,當退出理由為 :normal
、:shutdown
或 {:shutdown, term}
時,GenServers 等行為不會發出錯誤記錄。
因此,有人可能會問:我應該選擇哪個退出理由?有三個選項
:normal
- 在這種情況下,退出不會被記錄,在暫態模式下沒有重新啟動,連結的程序也不會退出:shutdown
或{:shutdown, term}
- 在這種情況下,退出不會被記錄,在暫態模式下沒有重新啟動,連結的程序會以相同的理由退出,除非它們正在捕捉退出任何其他術語 - 在這種情況下,退出將被記錄,在暫態模式下有重新啟動,連結的程序會以相同的理由退出,除非它們正在捕捉退出
一般來說,如果你要因為預期的原因而退出,你會想要使用 :shutdown
或 {:shutdown, term}
。
請注意,達到最大重新啟動強度的監督程式會以 :shutdown
原因退出。在這種情況下,只有當其子規格被定義為 :restart
選項設為 :permanent
(預設)時,監督程式才會重新啟動。
摘要
類型
支援的自動關機選項。
子程序。
監督程式子規格。
提供給 start_link/2
和 init/1
的選項。
基於模組的子規格。
監督程式名稱。
start_link/2
和 start_link/3
的回傳值。
start_link/2
和 start_link/3
函式使用的選項值。
支援的重新啟動選項。
支援的關機選項。
支援的策略。
初始化時回傳的監督程式旗標。
監督程式參考。
受監督子項目的類型。
回呼
呼叫回呼以啟動監督程式和在熱程式碼升級期間。
函式
建立並覆寫子規格。
回傳包含給定監督程式計數值的映射。
刪除由 child_id
識別的子規格。
接收要初始化的子規格清單和一組 options
。
重新啟動由 child_id
識別的子程序。
將子規格新增至 supervisor
並啟動該子項。
使用指定的子項啟動監督者。
使用指定的 module
和 init_arg
啟動基於模組的監督者程序。
使用指定的 reason
同步停止指定的監督者。
終止由 child_id
識別的指定子項。
傳回清單,其中包含有關指定監督者所有子項的資訊。
類型
@type auto_shutdown() :: :never | :any_significant | :all_significant
支援的自動關機選項。
@type child() :: pid() | :undefined
子程序。
當子程序啟動時,它可以是 PID,或是在 動態監督者 建立子項時為 :undefined
。
@type child_spec() :: %{ :id => atom() | term(), :start => {module(), function_name :: atom(), args :: [term()]}, optional(:restart) => restart(), optional(:shutdown) => shutdown(), optional(:type) => type(), optional(:modules) => [module()] | :dynamic, optional(:significant) => boolean() }
監督程式子規格。
它定義監督者應如何啟動、停止和重新啟動其每個子項。
@type init_option() :: {:strategy, strategy()} | {:max_restarts, non_neg_integer()} | {:max_seconds, pos_integer()} | {:auto_shutdown, auto_shutdown()}
提供給 start_link/2
和 init/1
的選項。
基於模組的子規格。
這是子項規格的一種形式,除了正規化的 child_spec/0
之外,您還可以將其傳遞給函式,例如 child_spec/2
、start_child/2
和 start_link/2
。
基於模組的子項規格可以是
模組 — 監督者呼叫
module.child_spec([])
以擷取子項規格二元組,其形狀為
{module, arg}
— 監督者呼叫module.child_spec(arg)
以擷取子項規格
監督程式名稱。
@type on_start() :: {:ok, pid()} | :ignore | {:error, {:already_started, pid()} | {:shutdown, term()} | term()}
start_link/2
和 start_link/3
的回傳值。
@type on_start_child() :: {:ok, child()} | {:ok, child(), info :: term()} | {:error, {:already_started, child()} | :already_present | term()}
start_child/2
的回傳值。
@type option() :: {:name, name()}
start_link/2
和 start_link/3
函式使用的選項值。
@type restart() :: :permanent | :transient | :temporary
支援的重新啟動選項。
@type shutdown() :: timeout() | :brutal_kill
支援的關機選項。
@type strategy() :: :one_for_one | :one_for_all | :rest_for_one
支援的策略。
@type sup_flags() :: %{ strategy: strategy(), intensity: non_neg_integer(), period: pos_integer(), auto_shutdown: auto_shutdown() }
初始化時回傳的監督程式旗標。
監督程式參考。
@type type() :: :worker | :supervisor
受監督子項目的類型。
受監督的子項是工作者還是監督者。
回呼
@callback init(init_arg :: term()) :: {:ok, {sup_flags(), [child_spec() | (old_erlang_child_spec :: :supervisor.child_spec())]}} | :ignore
呼叫回呼以啟動監督程式和在熱程式碼升級期間。
開發人員通常在 init 回呼的結尾呼叫 Supervisor.init/2
以傳回正確的監督旗標。
函式
@spec child_spec( child_spec() | module_spec(), keyword() ) :: child_spec()
建立並覆寫子規格。
類似於 start_link/2
和 init/2
,它預期一個模組,{module, arg}
,或一個 子規範。
如果給定一個形狀為 {module, arg}
的二元組,則透過呼叫 module.child_spec(arg)
來擷取子規範。
如果給定一個模組,則透過呼叫 module.child_spec([])
來擷取子規範。
在擷取子規範後,overrides
上的欄位會直接套用至子規範。如果 overrides
具有未對應至任何子規範欄位的鍵,則會引發錯誤。
請參閱模組文件中的「子規範」章節,以取得所有可覆寫的鍵。
範例
此函式通常用於在監督樹中需要多次啟動同一個模組時設定 :id
選項
Supervisor.child_spec({Agent, fn -> :ok end}, id: {Agent, 1})
#=> %{id: {Agent, 1},
#=> start: {Agent, :start_link, [fn -> :ok end]}}
@spec count_children(supervisor()) :: %{ specs: non_neg_integer(), active: non_neg_integer(), supervisors: non_neg_integer(), workers: non_neg_integer() }
回傳包含給定監督程式計數值的映射。
此映射包含下列鍵
:specs
- 子項目的總數,不論存活與否:active
- 此監督者管理的所有積極執行的子程序計數:supervisors
- 所有監督者的計數,不論這些子監督者是否仍存活:workers
- 所有工作者的計數,不論這些子工作者是否仍存活
@spec delete_child(supervisor(), term()) :: :ok | {:error, error} when error: :not_found | :running | :restarting
刪除由 child_id
識別的子規格。
對應的子程序不得執行中;如果執行中,請使用 terminate_child/2
終止它。
如果成功,此函式會傳回 :ok
。如果未找到 child_id
,或如果目前的程序正在執行或重新啟動,此函式可能會傳回一個包含適當錯誤組的錯誤。
@spec init( [ child_spec() | module_spec() | (old_erlang_child_spec :: :supervisor.child_spec()) ], [ init_option() ] ) :: {:ok, {sup_flags(), [child_spec() | (old_erlang_child_spec :: :supervisor.child_spec())]}}
接收要初始化的子規格清單和一組 options
。
這通常會在基於模組的監督者的 init/1
回呼的結尾呼叫。請參閱模組文件中的「監督者策略和選項」和「基於模組的監督者」章節,以取得更多資訊。
此函式會傳回一個包含監督者旗標和子規範的組。
範例
def init(_init_arg) do
children = [
{Counter, 0}
]
Supervisor.init(children, strategy: :one_for_one)
end
選項
:strategy
- 監督策略選項。可以是:one_for_one
、:rest_for_one
或:one_for_all
:max_restarts
- 在時間範圍內允許的最大重新啟動次數。預設為3
。:max_seconds
-:max_restarts
適用的時間範圍(單位:秒)。預設為5
。:auto_shutdown
- 自動關閉選項。可以是:never
、:any_significant
或:all_significant
:strategy
選項為必填,預設允許在 5 秒內重新啟動最多 3 次。請查看 Supervisor
模組以取得可用策略的詳細說明。
@spec restart_child(supervisor(), term()) :: {:ok, child()} | {:ok, child(), term()} | {:error, error} when error: :not_found | :running | :restarting | term()
重新啟動由 child_id
識別的子程序。
子規格必須存在,且對應的子程序不得正在執行。
請注意,對於暫時子項,當子項終止時,子項規格會自動刪除,因此無法重新啟動此類子項。
如果子程序啟動函數傳回 {:ok, child}
或 {:ok, child, info}
,PID 會加入監督,而此函數會傳回相同的值。
如果子程序啟動函數傳回 :ignore
,PID 會保持設定為 :undefined
,而此函數會傳回 {:ok, :undefined}
。
如果找不到 child_id
,或如果目前的程序正在執行或重新啟動中,此函數可能會傳回包含適當錯誤元組的錯誤。
如果子程序啟動函數傳回錯誤元組或錯誤值,或如果它失敗,此函數會傳回 {:error, error}
。
@spec start_child( supervisor(), child_spec() | module_spec() | (old_erlang_child_spec :: :supervisor.child_spec()) ) :: on_start_child()
將子規格新增至 supervisor
並啟動該子項。
child_spec
應為有效的子規格。子程序將會根據子規格中定義的內容啟動。
如果已存在具有指定 ID 的子規格,child_spec
會被捨棄,而且此函數會傳回包含 :already_started
或 :already_present
的錯誤,分別表示對應的子程序正在執行或未執行。
如果子程序啟動函數傳回 {:ok, child}
或 {:ok, child, info}
,則子規格和 PID 會加入監督,而此函數會傳回相同的值。
如果子程序啟動函數傳回 :ignore
,子規格會加入監督,PID 會設定為 :undefined
,而此函數會傳回 {:ok, :undefined}
。
如果子程序啟動函數傳回錯誤元組或錯誤值,或如果它失敗,子規格會被捨棄,而此函數會傳回 {:error, error}
,其中 error
是包含錯誤和子規格資訊的術語。
@spec start_link( [ child_spec() | module_spec() | (old_erlang_child_spec :: :supervisor.child_spec()) ], [ option() | init_option() ] ) :: {:ok, pid()} | {:error, {:already_started, pid()} | {:shutdown, term()} | term()}
@spec start_link(module(), term()) :: on_start()
使用指定的子項啟動監督者。
children
是下列形式的清單
子規格(請參閱
child_spec/0
)模組,其中監督呼叫
module.child_spec([])
以擷取子規格(請參閱module_spec/0
)一個
{module, arg}
叢集,其中監督呼叫module.child_spec(arg)
以擷取子規格(請參閱module_spec/0
)一個(舊的)Erlang 風格子規格(請參閱
:supervisor.child_spec()
)
需要透過 :strategy
選項提供策略。請參閱「監督策略和選項」以取得範例和其他選項。
這些選項也可以用於註冊監督名稱。支援的值說明在 GenServer
模組文件中的「名稱註冊」區段中。
如果監督和所有子程序都已成功產生(如果每個子程序的啟動函數傳回 {:ok, child}
、{:ok, child, info}
或 :ignore
),此函數會傳回 {:ok, pid}
,其中 pid
是監督的 PID。如果監督已命名,且已存在具有指定名稱的程序,函數會傳回 {:error, {:already_started, pid}}
,其中 pid
是該程序的 PID。
如果任何子程序的啟動函數失敗或傳回錯誤叢集或錯誤值,監督會先以原因 :shutdown
終止所有已啟動的子程序,然後終止自身並傳回 {:error, {:shutdown, reason}}
。
請注意,使用此函數啟動的監督會連結至父程序,且不僅會在發生異常時退出,也會在父程序以 :normal
原因退出時退出。
使用指定的 module
和 init_arg
啟動基於模組的監督者程序。
若要啟動監督,init/1
回呼會在指定的 module
中呼叫,並將 init_arg
作為其引數。 init/1
回呼必須傳回一個監督規格,可以使用 init/2
函數建立該規格。
如果 init/1
回呼傳回 :ignore
,此函數也會傳回 :ignore
,且監督會以原因 :normal
終止。如果它失敗或傳回不正確的值,此函數會傳回 {:error, term}
,其中 term
是包含錯誤資訊的項目,且監督會以原因 term
終止。
也可以提供 :name
選項以註冊監督名稱,支援的值說明在 GenServer
模組文件中的「名稱註冊」區段中。
@spec stop(supervisor(), reason :: term(), timeout()) :: :ok
使用指定的 reason
同步停止指定的監督者。
如果監督以指定原因終止,它會傳回 :ok
。如果它以其他原因終止,呼叫會退出。
此函數會針對錯誤回報保留 OTP 語意。如果原因不是 :normal
、:shutdown
或 {:shutdown, _}
,就會記錄錯誤回報。
@spec terminate_child(supervisor(), term()) :: :ok | {:error, :not_found}
終止由 child_id
識別的指定子項。
如果有程序,就會終止程序。除非子程序是暫時的,否則會保留子程序規格。
非暫時的子程序可能會在稍後由監督程序重新啟動。也可以透過呼叫 restart_child/2
明確重新啟動子程序。使用 delete_child/2
移除子程序規格。
如果成功,此函數會傳回 :ok
。如果沒有給定子程序 ID 的子程序規格,此函數會傳回 {:error, :not_found}
。
@spec which_children(supervisor()) :: [ {term() | :undefined, child() | :restarting, :worker | :supervisor, [module()] | :dynamic} ]
傳回清單,其中包含有關指定監督者所有子項的資訊。
請注意,當在低記憶體條件下監督大量子程序時,呼叫此函數可能會導致記憶體不足例外狀況。
此函數會傳回 {id, child, type, modules}
叢集清單,其中
id
- 如子程序規格中所定義child
- 對應子程序的 PID,如果程序即將重新啟動,則為:restarting
,如果沒有此類程序,則為:undefined
type
-:worker
或:supervisor
,如子程序規格中所指定modules
- 如子程序規格中所指定