Spec-Zone.ru › Elixir 1.13

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

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

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

Надзиратель может быть запущен напрямую со списком подпроцессов с помощью 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 — целое число или атом, определяющий, как подпроцесс должен быть завершён (см. раздел «Значения завершения» ниже). Этот ключ необязателен и по умолчанию равен 5_000, если тип — :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 — идентификатор спецификации подпроцесса, по умолчанию — текущий модуль
  • :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.

Для динамического надзора за дочерними процессами см. 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*

strategy()

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

supervisor()

Ссылка на надзорщика

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

init(init_arg)

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

Функции

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)

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

which_children(supervisor)

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

Типы

child()Source

@type child() :: pid() | :undefined

child_spec()Source

@type 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()Source

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

Опции, передаваемые в start_link/2 и init/2

name()Source

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

Имя супервайзера

on_start()Source

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

Возвращаемые значения функций start_link

on_start_child()Source

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

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

option()Source

@type option() :: {:name, name()}

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

strategy()Source

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

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

supervisor()Source

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

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

Обработчики

init(init_arg)Source

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

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

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

Функции

child_spec(module_or_map, overrides)Source

@spec 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)Source

@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)Source

@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)Source

@spec 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

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

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

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

restart_child(supervisor, child_id)Source

@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)Source

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

@spec start_link([:supervisor.child_spec() | {module(), term()} | module()], [
  option() | init_option()
]) ::
  {:ok, pid()}
  | {:error, {:already_started, pid()} | {:shutdown, term()} | term()}
@spec 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 \\ [])Source

@spec start_link(module(), term(), [option()]) :: 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.

END_OF_DOCUMENT_MARKER

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

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

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

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

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

terminate_child(supervisor, child_id)Source

@spec terminate_child(supervisor(), term()) :: :ok | {:error, :not_found}

Завершает заданного дочернего процесса, идентифицированного по child_id.

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

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

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

which_children(supervisor)Source

@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 - как указано в спецификации дочернего процесса

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

Spec-Zone.ru

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