檢視原始碼 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

Counterstart_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 - 熱程式碼升級機制用於確定哪些程序正在使用特定模組的模組清單。它通常設定為 GenServerSupervisor 等行為的回呼模組。它會根據 :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]}
}

上面的映射定義了一個子程序,其 :idCounter,通過呼叫 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/2init/1 的選項。

基於模組的子規格。

監督程式名稱。

start_link/2start_link/3 的回傳值。

start_link/2start_link/3 函式使用的選項值。

支援的重新啟動選項。

支援的關機選項。

支援的策略。

初始化時回傳的監督程式旗標。

監督程式參考。

受監督子項目的類型。

回呼

呼叫回呼以啟動監督程式和在熱程式碼升級期間。

函式

建立並覆寫子規格。

回傳包含給定監督程式計數值的映射。

刪除由 child_id 識別的子規格。

接收要初始化的子規格清單和一組 options

重新啟動由 child_id 識別的子程序。

將子規格新增至 supervisor 並啟動該子項。

使用指定的子項啟動監督者。

使用指定的 moduleinit_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/2init/1 的選項。

連結至這個類型

module_spec()

檢視原始碼 (自 1.16.0 起)
@type module_spec() :: {module(), args :: term()} | module()

基於模組的子規格。

這是子項規格的一種形式,除了正規化的 child_spec/0 之外,您還可以將其傳遞給函式,例如 child_spec/2start_child/2start_link/2

基於模組的子項規格可以是

  • 模組 — 監督者呼叫 module.child_spec([]) 以擷取子項規格

  • 二元組,其形狀為 {module, arg} — 監督者呼叫 module.child_spec(arg) 以擷取子項規格

@type name() :: atom() | {:global, term()} | {:via, module(), term()}

監督程式名稱。

@type on_start() ::
  {:ok, pid()}
  | :ignore
  | {:error, {:already_started, pid()} | {:shutdown, term()} | term()}

start_link/2start_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/2start_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 supervisor() :: pid() | name() | {atom(), node()}

監督程式參考。

@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 以傳回正確的監督旗標。

函式

連結至這個函式

child_spec(module_or_map, overrides)

檢視原始碼
@spec child_spec(
  child_spec() | module_spec(),
  keyword()
) :: child_spec()

建立並覆寫子規格。

類似於 start_link/2init/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 - 所有工作者的計數,不論這些子工作者是否仍存活

連結至這個函式

delete_child(supervisor, child_id)

檢視原始碼
@spec delete_child(supervisor(), term()) :: :ok | {:error, error}
when error: :not_found | :running | :restarting

刪除由 child_id 識別的子規格。

對應的子程序不得執行中;如果執行中,請使用 terminate_child/2 終止它。

如果成功,此函式會傳回 :ok。如果未找到 child_id,或如果目前的程序正在執行或重新啟動,此函式可能會傳回一個包含適當錯誤組的錯誤。

連結至這個函式

init(children, options)

檢視原始碼 (自 1.5.0 起)
@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 模組以取得可用策略的詳細說明。

連結至這個函式

restart_child(supervisor, child_id)

檢視原始碼
@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}

連結至這個函式

start_child(supervisor, child_spec)

檢視原始碼
@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 是包含錯誤和子規格資訊的術語。

連結至這個函式

start_link(children, options)

檢視原始碼
@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 原因退出時退出。

連結至這個函式

start_link(module, init_arg, options \\ [])

檢視原始碼
@spec start_link(module(), term(), [option()]) :: on_start()

使用指定的 moduleinit_arg 啟動基於模組的監督者程序。

若要啟動監督,init/1 回呼會在指定的 module 中呼叫,並將 init_arg 作為其引數。 init/1 回呼必須傳回一個監督規格,可以使用 init/2 函數建立該規格。

如果 init/1 回呼傳回 :ignore,此函數也會傳回 :ignore,且監督會以原因 :normal 終止。如果它失敗或傳回不正確的值,此函數會傳回 {:error, term},其中 term 是包含錯誤資訊的項目,且監督會以原因 term 終止。

也可以提供 :name 選項以註冊監督名稱,支援的值說明在 GenServer 模組文件中的「名稱註冊」區段中。

連結至這個函式

stop(supervisor, reason \\ :normal, timeout \\ :infinity)

檢視原始碼
@spec stop(supervisor(), reason :: term(), timeout()) :: :ok

使用指定的 reason 同步停止指定的監督者。

如果監督以指定原因終止,它會傳回 :ok。如果它以其他原因終止,呼叫會退出。

此函數會針對錯誤回報保留 OTP 語意。如果原因不是 :normal:shutdown{:shutdown, _},就會記錄錯誤回報。

連結至這個函式

terminate_child(supervisor, child_id)

檢視原始碼
@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 - 如子程序規格中所指定