Наблюдатель поведение
Модуль поведения для реализации наблюдателей.
Наблюдатель — это процесс, который контролирует другие процессы, которые мы называем дочерними процессами. Наблюдатели используются для построения иерархической структуры процессов, называемой деревом наблюдения. Деревья наблюдения обеспечивают отказоустойчивость и инкапсулируют, как запускаются и завершаются наши приложения.
Наблюдатель может быть запущен непосредственно со списком дочерних элементов с помощью 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. Кроме того, каждый наблюдатель может иметь множество рабочих процессов и/или других наблюдателей в качестве дочерних элементов, причём каждый из них имеет собственные настройки (как указано в разделе «Спецификация дочернего элемента»).
В остальной части документации будет рассмотрено, как запускаются дочерние процессы, как их можно задать, какие существуют стратегии наблюдения и многое другое.
Запуск и завершение
При запуске наблюдателя он проходит по всем спецификациям дочерних элементов и запускает каждый дочерний элемент в порядке их определения. Это делается путём вызова функции, определённой в ключе :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, гарантируя, что он завершится в разумный срок.
Теперь, когда мы поняли процесс запуска и завершения, давайте подробно рассмотрим все параметры, предоставляемые в спецификации дочернего элемента.
Спецификация дочернего элемента
Спецификация дочернего элемента описывает, как наблюдатель запускает, завершает и перезапускает дочерние процессы.
Спецификация дочернего элемента содержит 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 отвечает за построение собственной спецификации. По умолчанию use GenServer определяет функцию Stack.child_spec/1, которая возвращает ту же спецификацию дочернего элемента, что и прежде:
%{
id: Stack,
start: {Stack, :start_link, [[:hello]]}
}Также можно просто передать модуль Stack в качестве дочернего элемента:
children = [ Stack ]
Если указано только имя модуля, это эквивалентно {Stack, []}. В этом случае мы получим спецификацию дочернего элемента, которая выглядит так:
%{
id: Stack,
start: {Stack, :start_link, [[]]}
}Заменив спецификацию карты на {Stack, [:hello]} или Stack, мы сохраняем спецификацию дочернего элемента, инкапсулированную в модуле Stack, используя реализацию по умолчанию, определённую в use GenServer. Теперь мы можем поделиться нашим рабочим процессом Stack с другими разработчиками, и они могут напрямую добавить его в своё дерево наблюдения, не беспокоясь о низкоуровневых деталях рабочего процесса.
В целом, спецификация дочернего элемента может быть одним из следующих:
- карта, представляющая саму спецификацию дочернего элемента — как указано в разделе «Спецификация дочернего элемента»
- кортеж с модулем в качестве первого элемента и аргументом запуска во втором — например,
{Stack, [:hello]}. В этом случае вызываетсяStack.child_spec([:hello])для получения спецификации дочернего элемента - модуль — например,
Stack. В этом случае вызываетсяStack.child_spec([])для получения спецификации дочернего элемента
Если вам нужно преобразовать спецификацию дочернего элемента типа кортеж или модуль в карту или изменить её, вы можете использовать функцию Supervisor.child_spec/2. Например, для запуска стека с другим значением :id и значением :shutdown в 10 секунд (10000 миллисекунд):
children = [
Supervisor.child_spec({Stack, [:hello]}, id: MyStack, shutdown: 10_000)
]Вызов Supervisor.child_spec/2 выше вернёт следующее описание:
%{
id: MyStack,
start: {Stack, :start_link, [[:hello]]},
shutdown: 10_000
} Вы также можете настроить описание дочернего процесса в самом модуле Stack, чтобы использовать другое значение :id или :shutdown, передав опции в use GenServer:
defmodule Stack do use GenServer, id: MyStack, shutdown: 10_000
Вышеперечисленные опции настроят функцию Stack.child_spec/1, определённую в use GenServer. Она принимает те же опции, что и функция Supervisor.child_spec/2.
Вы также можете полностью переопределить функцию child_spec/1 в модуле Stack и вернуть собственное описание дочернего процесса. Обратите внимание, что нет гарантии, что функция child_spec/1 будет вызвана процессом-надсмотрщиком, так как другие процессы могут вызвать её для получения описания дочернего процесса до обращения к надсмотрщику.
Причины завершения и перезапуски
Надсмотрщик перезапускает дочерний процесс в зависимости от его конфигурации :restart. Например, когда :restart установлено в :transient, надсмотрщик не перезапускает дочерний процесс в случае его завершения с причиной :normal, :shutdown или {:shutdown, term}.
Поэтому возникает вопрос: какую причину завершения выбрать? Есть три варианта:
-
:normal— в таких случаях завершение не будет записано в журнал, перезапуска в режиме временного состояния не будет, и связанные процессы не завершатся. -
:shutdownили{:shutdown, term}— в таких случаях завершение не будет записано в журнал, перезапуска в режиме временного состояния не будет, и связанные процессы завершатся с той же причиной, если они не отлавливают завершения. -
любой другой термин — в таких случаях завершение будет записано в журнал, перезапуска в режиме временного состояния будут, и связанные процессы завершатся с той же причиной, если они не отлавливают завершения.
Обратите внимание, что надсмотрщик, достигающий максимальной интенсивности перезапусков, завершится с причиной :shutdown. В этом случае надсмотрщик будет перезапущен только в том случае, если его описание дочернего процесса было определено с опцией :restart установленной в :permanent (по умолчанию).
Модульные надсмотрщики
В примере выше, надсмотрщик был запущен путём передачи структуры надзора функции start_link/2. Однако, надсмотрщики также могут быть созданы путём явного определения модуля надзора:
defmodule MyApp.Supervisor do
# Automatically defines child_spec/1
use Supervisor
def start_link(arg) do
Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
end
@impl true
def 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 можно настроить с помощью следующих опций:
-
:id— идентификатор описания дочернего процесса, по умолчанию — текущий модуль -
:start— способ запуска дочернего процесса (по умолчанию — вызов__MODULE__.start_link/1) -
:restart— когда надсмотрщик должен быть перезапущен, по умолчанию —:permanent
start_link/2, init/2, и стратегии
До сих пор мы запускали надсмотрщика, передавая единственный дочерний процесс как кортеж, а также стратегию под названием :one_for_one:
Supervisor.start_link([
{Stack, [:hello]}
], strategy: :one_for_one) или изнутри обратного вызова init/1:
Supervisor.init([
{Stack, [:hello]}
], 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.
Обзор
Типы
- 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)
-
Получает список дочерних процессов для инициализации и набор опций
- restart_child(supervisor, child_id)
-
Перезапускает дочерний процесс, идентифицированный по
child_id - start_child(supervisor, child_spec)
-
Добавляет описание дочернего процесса к
supervisorи запускает этот дочерний процесс - start_link(children, options)
-
Запускает надсмотрщика с заданными дочерними процессами
- start_link(module, arg, options \\ [])
-
Запускает процесс модульного надсмотрщика с заданным
moduleиarg - stop(supervisor, reason \\ :normal, timeout \\ :infinity)
-
Синхронно останавливает данный надсмотрщик с указанной
reason - terminate_child(supervisor, child_id)
-
Завершает заданный дочерний процесс, идентифицированный по идентификатору
- which_children(supervisor)
-
Возвращает список с информацией обо всех дочерних процессах данного надсмотрщика
Обратные вызовы
- init(args)
-
Обратный вызов, вызываемый для запуска надсмотрщика и во время горячих обновлений кода
Типы
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()} Принимает список дочерних процессов для инициализации и набор параметров.
Обычно вызывается в конце обратного вызова init/1 супервайзеров на основе модулей. См. разделы «Супервайзеры на основе модулей» и «start_link/2, init/2 и стратегии» в документации модуля для получения дополнительной информации.
Функция возвращает кортеж, содержащий флаги супервайзера и спецификации дочерних процессов.
Примеры
def init(_arg) do
Supervisor.init([
{Stack, [:hello]}
], 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 должна быть корректной спецификацией дочернего процесса. Дочерний процесс будет запущен в соответствии с определением в спецификации дочернего процесса.
Если спецификация дочернего процесса с указанным идентификатором уже существует, 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(module(), term()) :: on_start()
start_link(
[:supervisor.child_spec() | {module(), term()} | module()],
options()
) :: 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, arg, options \\ [])
start_link(module(), term(), GenServer.options()) :: on_start()
Запускает процесс супервайзера на основе модуля с заданными module и arg.
Для запуска супервайзера вызывается обратный вызов init/1 в данном module, с 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 Завершает указанного ребёнка, идентифицированного по 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(args)
init(args :: 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.7.4/Supervisor.html