Spec-Zone.ru › Elixir 1.8

Наблюдатель поведение

Модуль поведения для реализации наблюдателей.

Наблюдатель — это процесс, который наблюдает за другими процессами, которые мы называем дочерними процессами. Наблюдатели используются для построения иерархической структуры процессов, называемой деревом наблюдения. Деревья наблюдения обеспечивают отказоустойчивость и инкапсулируют запуск и завершение наших приложений.

Наблюдатель может быть запущен напрямую со списком дочерних процессов с помощью start_link/2, или вы можете определить наблюдатель на основе модуля, реализующего необходимые обратные вызовы. В следующих разделах используется start_link/2 для запуска наблюдателей в большинстве примеров, но также представлен отдельный раздел о наблюдателях на основе модулей.

Примеры

Для запуска наблюдателя нам необходимо сначала определить дочерний процесс, который будет наблюдаться. В качестве примера мы определим GenServer, представляющий собой стек:

defmodule Stack do
  use GenServer

  def start_link(state) do
    GenServer.start_link(__MODULE__, state, name: __MODULE__)
  end

  ## Callbacks

  @impl true
  def init(stack) do
    {:ok, stack}
  end

  @impl true
  def handle_call(:pop, _from, [head | tail]) do
    {:reply, head, tail}
  end

  @impl true
  def handle_cast({:push, head}, tail) do
    {:noreply, [head | tail]}
  end
end

Стек — это небольшой оболочкой над списками. Он позволяет нам поместить элемент на вершину стека, добавив его в начало списка, и получить вершину стека с помощью сопоставления шаблонов.

Теперь мы можем запустить наблюдатель, который будет запускать и наблюдать за нашим процессом стека. Первым шагом является определение списка спецификаций дочерних процессов, которые управляют поведением каждого дочернего процесса. Каждая спецификация дочернего процесса — это карта, как показано ниже:

children = [
  # The Stack is a child started via Stack.start_link([:hello])
  %{
    id: Stack,
    start: {Stack, :start_link, [[:hello]]}
  }
]

# 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 мы регистрируем его с именем Stack, что позволяет нам напрямую обратиться к нему и получить содержимое стека:

GenServer.call(Stack, :pop)
#=> :hello

GenServer.cast(Stack, {:push, :world})
#=> :ok

GenServer.call(Stack, :pop)
#=> :world

Однако в нашем сервере стека есть ошибка. Если мы вызываем :pop, а стек пуст, произойдёт сбой, так как ни один шаблон не соответствует:

GenServer.call(Stack, :pop)
** (exit) exited in: GenServer.call(Stack, :pop, 5000)

К счастью, поскольку сервер контролируется наблюдателем, наблюдатель автоматически запустит новый сервер со стоковым значением [:hello]:

GenServer.call(Stack, :pop)
#=> :hello

Наблюдатели поддерживают различные стратегии; в приведенном выше примере мы выбрали :one_for_one. Кроме того, каждый наблюдатель может иметь множество рабочих процессов и/или других наблюдателей в качестве дочерних процессов, каждый из которых имеет собственную конфигурацию (как описано в разделе «Спецификация дочерних процессов»).

В оставшейся части документации будет описано, как задаются параметры дочерних процессов, как они могут быть запущены и остановлены, различные стратегии наблюдения и многое другое.

Спецификация дочернего процесса

Спецификация дочернего процесса описывает, как наблюдатель запускает, останавливает и перезапускает дочерние процессы.

Спецификация дочернего процесса содержит 6 ключей. Первые два обязательны, а остальные — необязательны:

  • :id — любое значение, используемое для идентификации спецификации дочернего процесса внутри наблюдателя; по умолчанию совпадает с заданным модулем. В случае конфликтующих значений :id, наблюдатель откажется от инициализации и потребует явных идентификаторов. Этот ключ обязателен.

  • :start — кортеж с модулем-функцией-аргументами, которые вызываются для запуска дочернего процесса. Этот ключ обязателен.

  • :restart — атом, определяющий, когда завершившийся дочерний процесс должен быть перезапущен (см. раздел «Значения перезапуска» ниже). Этот ключ необязателен и по умолчанию равен :permanent.

  • :shutdown — атом, определяющий, как должен быть завершён дочерний процесс (см. раздел «Значения завершения» ниже). Этот ключ необязателен и по умолчанию равен 5000 для типа :worker, или :infinity для типа :supervisor.

  • :type — указывает, что дочерний процесс является :worker или :supervisor процессом. Этот ключ необязателен и по умолчанию равен :worker.

Существует шестой ключ, :modules, который редко изменяется. Он устанавливается автоматически на основе значения в :start.

Давайте разберёмся, за что отвечают опции :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: Stack,
  start: {Stack, :start_link, [[:hello]]}
}

Приведенная выше карта определяет наблюдатель с :id из Stack, который запускается вызовом Stack.start_link([:hello]).

Однако задание спецификаций дочерних процессов для каждого дочернего процесса в виде карты может быть довольно подвержено ошибкам, так как мы можем изменить реализацию стека и забыть обновить его спецификацию. Вот почему Elixir позволяет вам передавать кортеж с именем модуля и аргументом start_link вместо спецификации:

children = [
  {Stack, [:hello]}
]

Наблюдатель затем вызовет Stack.child_spec([:hello]) для получения спецификации дочернего процесса. Теперь модуль Stack отвечает за построение собственной спецификации, например, мы можем написать:

def child_spec(arg) do
  %{
    id: Stack,
    start: {Stack, :start_link, [arg]}
  }
end

К счастью для нас, use GenServer уже определяет Stack.child_spec/1 точно так же, как выше. Если вам нужно настроить GenServer, вы можете передать параметры напрямую в use GenServer:

use GenServer, restart: :transient

Наконец, обратите внимание, что также можно просто передать модуль Stack в качестве дочернего процесса:

children = [
  Stack
]

При передаче только имени модуля это эквивалентно {Stack, []}. Заменив спецификацию карты на {Stack, [:hello]} или Stack, мы сохраняем спецификацию дочернего процесса, инкапсулированную в модуле Stack, используя реализацию по умолчанию, определённую в use GenServer. Теперь мы можем поделиться нашим рабочим процессом Stack с другими разработчиками, и они могут добавить его напрямую в своё дерево наблюдения, не беспокоясь о низкоуровневых деталях работы.

В целом, спецификация дочернего процесса может быть одной из следующих:

  • карта, представляющая саму спецификацию дочернего процесса — как описано в разделе «Спецификация дочернего процесса»
  • кортеж с модулем в качестве первого элемента и аргументом запуска как второго — например, {Stack, [:hello]}. В этом случае вызывается Stack.child_spec([:hello]) для получения спецификации дочернего процесса
  • модуль — например, Stack. В этом случае вызывается Stack.child_spec([]) для получения спецификации дочернего процесса

Если вам нужно преобразовать спецификацию дочернего процесса в виде кортежа или модуля в карту или изменить её, вы можете использовать функцию Supervisor.child_spec/2. Например, чтобы запустить стек с другим :id и значением :shutdown 10 секунд (10 000 миллисекунд):

children = [
  Supervisor.child_spec({Stack, [:hello]}, id: MyStack, shutdown: 10_000)
]

Модульные наблюдатели

В примере выше наблюдатель запускался путём передачи структуры наблюдения в 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 = [
      {Stack, [:hello]}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end

Разница между двумя подходами заключается в том, что наблюдатель на основе модуля даёт вам больший контроль над инициализацией наблюдателя. Вместо вызова Supervisor.start_link/2 со списком дочерних процессов, которые автоматически инициализируются, мы вручную инициализируем дочерние процессы, вызвав Supervisor.init/2 внутри его обратного вызова init/1.

use Supervisor также определяет функцию child_spec/1 , которая позволяет нам запускать MyApp.Supervisor в качестве дочернего процесса другого наблюдателя или в верхней части вашего дерева наблюдения, как в следующем примере:

children = [
  MyApp.Supervisor
]

Supervisor.start_link(children, strategy: :one_for_one)

Общее руководство — использовать наблюдателя без модуля обратного вызова только в верхней части вашего дерева наблюдения, обычно в обратном вызове Application.start/2. Мы рекомендуем использовать модульные наблюдатели для всех других наблюдателей в вашем приложении, чтобы они могли работать как дочерние процессы другого наблюдателя в дереве. child_spec/1 автоматически генерируется Supervisor и может быть настроен с помощью следующих параметров:

  • :id — идентификатор спецификации дочернего процесса, по умолчанию совпадает с текущим модулем
  • :start — как запустить дочерний процесс (по умолчанию вызывается __MODULE__.start_link/1)
  • :restart — когда наблюдатель должен быть перезапущен, по умолчанию :permanent

Аннотация @doc, непосредственно предшествующая use Supervisor, будет присоединена к сгенерированной функции child_spec/1.

start_link/2, init/2, и стратегии

До сих пор мы запускали надзорный процесс, передавая единственного потомка в виде кортежа, а также стратегию под названием :one_for_one:

children = [
  {Stack, [:hello]}
]

Supervisor.start_link(children, strategy: :one_for_one)

или изнутри обратного вызова init/1:

children = [
  {Stack, [:hello]}
]

Supervisor.init(children, strategy: :one_for_one)

Первый аргумент, передаваемый функциям start_link/2 и init/2, представляет собой список спецификаций потомков, как определено в разделе "child_spec/1" выше.

Второй аргумент — это список ключевых слов с опциями:

  • :strategy — опция стратегии управления. Может быть :one_for_one, :rest_for_one или :one_for_all. Требуется. См. раздел "Стратегии".

  • :max_restarts — максимальное количество перезапусков, разрешенных в рамках временного интервала. По умолчанию 3.

  • :max_seconds — временной интервал, в котором действует :max_restarts. По умолчанию 5.

  • :name — имя для регистрации процесса надзирателя. Допустимые значения описаны в разделе "Регистрация имён" в документации для GenServer. Необязательно.

Стратегии

Надзиратели поддерживают различные стратегии управления (через опцию :strategy, как показано выше):

  • :one_for_one — если дочерний процесс завершается, перезапускается только этот процесс.

  • :one_for_all — если дочерний процесс завершается, все другие дочерние процессы завершаются, а затем все дочерние процессы (включая завершившийся) перезапускаются.

  • :rest_for_one — если дочерний процесс завершается, завершается этот процесс и все дочерние процессы, запущенные после него, а затем все они перезапускаются.

В приведенном выше примере завершение процесса относится к неудачному завершению, которое определяется опцией :restart.

Также существует устаревшая стратегия под названием :simple_one_for_one, которая была заменена на DynamicSupervisor. Надзиратель :simple_one_for_one был похож на :one_for_one, но лучше подходит для динамического подключения дочерних процессов. Многие функции в этом модуле вели себя немного по-другому при использовании этой стратегии. См. модуль DynamicSupervisor для получения дополнительной информации и стратегий миграции.

Регистрация имён

Надзиратель подчиняется тем же правилам регистрации имён, что и GenServer. Подробнее об этих правилах см. в документации для GenServer.

Запуск и завершение

При запуске надзирателя он обходит все спецификации дочерних процессов, а затем запускает каждый дочерний процесс в порядке их определения. Это делается путем вызова функции, определенной под ключом :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} — в таких случаях выход не регистрируется, перезапуска нет в переходном режиме, и связанные процессы завершаются с той же причиной, если только они не обрабатывают сигналы выхода.

  • любое другое значение — в таких случаях выход регистрируется, есть перезапуски в переходном режиме, и связанные процессы завершаются с той же причиной, если только они не обрабатывают сигналы выхода.

Обратите внимание, что надзиратель, достигший максимальной интенсивности перезапуска, выйдет с причиной :shutdown. В этом случае надзиратель будет перезапущен только в том случае, если его спецификация дочернего процесса была определена с опцией :restart установленной в значение :permanent (по умолчанию).

Резюме

Типы

child()
child_spec()

Спецификация надзирателя

init_option()

Опции, передаваемые функциям start_link/2 и init/2

name()

Имя надзирателя

on_start()

Значения возврата функций start_link

on_start_child()

Значения возврата функций start_child

option()

Значения опций, используемых функциями start*

options()

Опции, используемые функциями start*

strategy()

Поддерживаемые стратегии

supervisor()

Ссылка на надзирателя

Функции

child_spec(module_or_map, overrides)

Создает и переопределяет спецификацию дочернего процесса.

count_children(supervisor)

Возвращает карту, содержащую значения счетчиков для данного надзирателя.

delete_child(supervisor, child_id)

Удаляет спецификацию дочернего процесса, идентифицированную по child_id.

init(children, options)

Получает список children для инициализации и набор options.

restart_child(supervisor, child_id)

Перезапускает дочерний процесс, идентифицированный по child_id.

start_child(supervisor, child_spec)

Добавляет спецификацию дочернего процесса к supervisor и запускает этот дочерний процесс.

start_link(children, options)

Запускает надзирателя с заданными дочерними процессами.

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

Запускает процесс надзирателя на основе модуля с заданным module и init_arg.

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

Синхронно останавливает указанный надзиратель с заданной reason.

terminate_child(supervisor, child_id)

Завершает указанный дочерний процесс по идентификатору.

which_children(supervisor)

Возвращает список с информацией обо всех дочерних процессах данного надзирателя.

Обратные вызовы

init(init_arg)

Обратный вызов, вызываемый при запуске надзирателя и во время горячих обновлений кода.

Типы

child()

child() :: pid() | :undefined

child_spec()

child_spec() :: %{
  :id => atom() | term(),
  :start => {module(), atom(), [term()]},
  optional(:restart) => :permanent | :transient | :temporary,
  optional(:shutdown) => timeout() | :brutal_kill,
  optional(:type) => :worker | :supervisor,
  optional(:modules) => [module()] | :dynamic
}

Спецификация надзирателя

init_option()

init_option() ::
  {:strategy, strategy()}
  | {:max_restarts, non_neg_integer()}
  | {:max_seconds, pos_integer()}

Опции, передаваемые функциям start_link/2 и init/2

name()

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

Имя надзирателя

on_start()

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

Значения возврата функций start_link

on_start_child()

on_start_child() ::
  {:ok, child()}
  | {:ok, child(), info :: term()}
  | {:error, {:already_started, child()} | :already_present | term()}

Значения возвращаемых start_child функций

option()

option() :: {:name, name()} | init_option()

Значения параметров, используемые start* функциями

options()

options() :: [option(), ...]

Параметры, используемые start* функциями

strategy()

strategy() :: :one_for_one | :one_for_all | :rest_for_one

Поддерживаемые стратегии

supervisor()

supervisor() :: pid() | name() | {atom(), node()}

Ссылка на супервайзера

Функции

child_spec(module_or_map, overrides)

child_spec(child_spec() | {module(), arg :: term()} | module(), keyword()) ::
  child_spec()

Создаёт и перезаписывает спецификацию дочернего процесса.

Аналогично start_link/2 и init/2, ожидает module, {module, arg} или карту в качестве спецификации дочернего процесса. Если указан модуль, спецификация извлекается путём вызова module.child_spec(arg).

После извлечения спецификации дочернего процесса, поля overrides напрямую применяются к спецификации. Если overrides содержит ключи, которые не соответствуют полям спецификации дочернего процесса, генерируется ошибка.

Все доступные ключи для перезаписи см. в разделе "Спецификация дочернего процесса" в документации модуля.

Примеры

Эта функция часто используется для установки параметра :id при необходимости запуска одного и того же модуля несколько раз в дереве супервайзеров:

Supervisor.child_spec({Agent, fn -> :ok end}, id: {Agent, 1})
#=> %{id: {Agent, 1},
#=>   start: {Agent, :start_link, [fn -> :ok end]}}

count_children(supervisor)

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)

delete_child(supervisor(), term()) :: :ok | {:error, error}
when error: :not_found | :simple_one_for_one | :running | :restarting

Удаляет спецификацию дочернего процесса, идентифицированную по child_id.

Соответствующий дочерний процесс не должен выполняться; используйте terminate_child/2 для его завершения, если он запущен.

При успешном выполнении функция возвращает :ok. Эта функция может возвращать ошибку с соответствующим кортежем ошибки, если child_id не найден, или если текущий процесс выполняется или перезапускается.

init(children, options)

(since 1.5.0)
init([:supervisor.child_spec() | {module(), term()} | module()], [init_option()]) ::
  {:ok, tuple()}

Принимает список children для инициализации и набор options.

Обычно вызывается в конце обратного вызова init/1 супервайзеров на основе модулей. Подробнее см. разделы "Супервайзеры на основе модулей" и "start_link/2, init/2 и стратегии" в документации модуля.

Функция возвращает кортеж, содержащий флаги супервайзера и спецификации дочерних процессов.

Примеры

def init(_init_arg) do
  children = [
    {Stack, [:hello]}
  ]

  Supervisor.init(children, strategy: :one_for_one)
end

Параметры

  • :strategy - параметр стратегии супервайзера. Может быть :one_for_one, :rest_for_one, :one_for_all, или устаревший :simple_one_for_one.

  • :max_restarts - максимальное количество перезапусков, разрешенных в течение определённого промежутка времени. По умолчанию 3.

  • :max_seconds - промежуток времени в секундах, в течение которого применяется :max_restarts . По умолчанию 5.

Параметр :strategy обязателен и по умолчанию позволяет максимум 3 перезапуска в течение 5 секунд. Подробное описание доступных стратегий см. в модуле Supervisor.

restart_child(supervisor, child_id)

restart_child(supervisor(), term()) ::
  {:ok, child()} | {:ok, child(), term()} | {:error, error}
when error: :not_found | :simple_one_for_one | :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)

start_child(
  supervisor(),
  :supervisor.child_spec() | {module(), term()} | module() | [term()]
) :: 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)

start_link(
  [:supervisor.child_spec() | {module(), term()} | module()],
  options()
) :: on_start()
start_link(module(), term()) :: on_start()

Запускает супервайзера с заданными дочерними процессами.

Children — список модулей, двухэлементных кортежей (модуль и аргументы) или карта со спецификацией дочернего процесса. Стратегия должна быть указана через параметр :strategy . Примеры и другие параметры см. в разделе «start_link/2, init/2 и стратегии».

Параметры также могут использоваться для регистрации имени супервайзера. Поддерживаемые значения описаны в разделе «Регистрация имени» в документации модуля 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 \\ [])

start_link(module(), term(), GenServer.options()) :: on_start()

Запускает процесс супервайзера на основе модуля с заданным module и init_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)

stop(supervisor(), reason :: term(), timeout()) :: :ok

Синхронно останавливает заданный супервайзер с заданным reason.

Возвращает :ok , если супервайзер завершается с указанным кодом. Если он завершается с другим кодом, вызов завершается.

Эта функция сохраняет семантику OTP в отношении отчётности об ошибках. Если код — любой, кроме :normal, :shutdown или {:shutdown, _}, регистрируется отчёт об ошибке.

terminate_child(supervisor, child_id)

terminate_child(supervisor(), term()) :: :ok | {:error, error}
when error: :not_found | :simple_one_for_one

Завершает заданный дочерний процесс, идентифицированный по child id.

Процесс завершается, если он существует. Спецификация дочернего процесса сохраняется, если только дочерний процесс не является временным.

Процесс дочернего процесса, который не является временным, может быть позже перезапущен супервайзером. Дочерний процесс также может быть перезапущен явно путём вызова restart_child/2. Используйте delete_child/2 для удаления спецификации дочернего процесса.

При успешном выполнении функция возвращает :ok. Если для заданного идентификатора дочернего процесса нет спецификации, функция возвращает {:error, :not_found}.

which_children(supervisor)

which_children(supervisor()) :: [
  {term() | :undefined, child() | :restarting, :worker | :supervisor,
   :supervisor.modules()}
]

Возвращает список с информацией обо всех детях заданного надзирателя.

Обратите внимание, что вызов этой функции при надзоре за большим количеством детей в условиях низкой памяти может привести к исключению из-за недостатка памяти.

Функция возвращает список кортежей {id, child, type, modules}, где:

  • id - как определено в спецификации дочернего процесса

  • child - идентификатор процесса (PID) соответствующего дочернего процесса, :restarting если процесс готов к перезапуску, или :undefined если такого процесса нет

  • type - :worker или :supervisor, как указано в спецификации дочернего процесса

  • modules - как указано в спецификации дочернего процесса

Обработчики событий

init(init_arg)

init(init_arg :: term()) ::
  {:ok, {:supervisor.sup_flags(), [:supervisor.child_spec()]}} | :ignore

Обработчик, вызываемый для запуска надзирателя и во время горячих обновлений кода.

Разработчики обычно вызывают Supervisor.init/2 в конце своего обработчика init, чтобы вернуть соответствующие флаги надзора.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.8.2/Supervisor.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API