DynamicSupervisor поведение
Наблюдатель, который динамически запускает дочерние процессы.
Модуль Supervisor был разработан для обработки в основном статических дочерних процессов, которые запускаются в заданном порядке при запуске наблюдателя. DynamicSupervisor запускается без дочерних процессов. Вместо этого, дочерние процессы запускаются по требованию с помощью start_child/2. При завершении работы динамического наблюдателя все дочерние процессы завершаются одновременно, без гарантии порядка.
Примеры
Динамический наблюдатель запускается без дочерних процессов, стратегии наблюдения (в настоящее время поддерживается только стратегия :one_for_one) и имени:
children = [
{DynamicSupervisor, strategy: :one_for_one, name: MyApp.DynamicSupervisor}
]
Supervisor.start_link(children, strategy: :one_for_one)
Параметры, указанные в спецификации дочернего процесса, описаны в start_link/1.
После запуска динамического наблюдателя мы можем запустить дочерние процессы с помощью start_child/2, который получает спецификацию дочернего процесса:
{:ok, agent1} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})
Agent.update(agent1, &Map.put(&1, :key, "value"))
Agent.get(agent1, & &1)
#=> %{key: "value"}
{:ok, agent2} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})
Agent.get(agent2, & &1)
#=> %{}
DynamicSupervisor.count_children(MyApp.DynamicSupervisor)
#=> %{active: 2, specs: 2, supervisors: 0, workers: 2}
Наблюдатели на основе модулей
Аналогично Supervisor, динамические наблюдатели также поддерживают наблюдатели на основе модулей.
defmodule MyApp.DynamicSupervisor do
# Automatically defines child_spec/1
use DynamicSupervisor
def start_link(init_arg) do
DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@impl true
def init(_init_arg) do
DynamicSupervisor.init(strategy: :one_for_one)
end
end
См. документацию Supervisor для обсуждения случаев, когда вы можете использовать наблюдателей на основе модулей. Аннотация @doc непосредственно перед use DynamicSupervisor будет добавлена к сгенерированной функции child_spec/1.
Регистрация имени
Наблюдатель подчиняется тем же правилам регистрации имени, что и GenServer. Подробнее об этих правилах см. в документации для GenServer.
Миграция из :simple_one_for_one
В случае использования устаревшей стратегии :simple_one_for_one из модуля Supervisor, вы можете перейти к DynamicSupervisor несколькими шагами.
Представьте данный "старый" код:
defmodule MySupervisor do
use Supervisor
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
def start_child(foo, bar, baz) do
# This will start child by calling MyWorker.start_link(init_arg, foo, bar, baz)
Supervisor.start_child(__MODULE__, [foo, bar, baz])
end
@impl true
def init(init_arg) do
children = [
# Or the deprecated: worker(MyWorker, [init_arg])
%{id: MyWorker, start: {MyWorker, :start_link, [init_arg]}}
]
Supervisor.init(children, strategy: :simple_one_for_one)
end
end
Он может быть обновлен до DynamicSupervisor следующим образом:
defmodule MySupervisor do
use DynamicSupervisor
def start_link(init_arg) do
DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
def start_child(foo, bar, baz) do
# If MyWorker is not using the new child specs, we need to pass a map:
# spec = %{id: MyWorker, start: {MyWorker, :start_link, [foo, bar, baz]}}
spec = {MyWorker, foo: foo, bar: bar, baz: baz}
DynamicSupervisor.start_child(__MODULE__, spec)
end
@impl true
def init(init_arg) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: [init_arg]
)
end
end
Разница в том, что DynamicSupervisor ожидает спецификацию дочернего процесса в момент вызова start_child/2, а не в обработчике init. Если при инициализации передаются какие-либо начальные аргументы, такие как [initial_arg], их можно передать в флаге :extra_arguments функции DynamicSupervisor.init/1.
Резюме
Типы
- init_option()
Параметры, передаваемые функциям
start_linkиinit/1- on_start_child()
Возвращаемые значения функций
start_child- option()
Параметры, передаваемые функциям
start_link- strategy()
Поддерживаемые стратегии
- sup_flags()
Флаги наблюдателя, возвращаемые при инициализации
Обработчики
- init(init_arg)
Обработчик, вызываемый для запуска наблюдателя и во время горячих обновлений кода.
Функции
- child_spec(opts)
Возвращает спецификацию для запуска динамического наблюдателя под наблюдателем.
- count_children(supervisor)
Возвращает карту, содержащую значения подсчета для наблюдателя.
- init(options)
Принимает набор
optionsдля инициализации динамического наблюдателя.- start_child(supervisor, child_spec)
Динамически добавляет спецификацию дочернего процесса к
supervisorи запускает этот дочерний процесс.- start_link(options)
Запускает наблюдателя с заданными параметрами.
- start_link(mod, init_arg, opts \\ [])
Запускает процесс наблюдателя на основе модуля с заданными
moduleиarg.- stop(supervisor, reason \\ :normal, timeout \\ :infinity)
Синхронно останавливает заданный наблюдатель с заданным
reason.- terminate_child(supervisor, pid)
Завершает заданный дочерний процесс, идентифицированный по
pid.- which_children(supervisor)
Возвращает список с информацией обо всех дочерних процессах.
Типы
init_option()Source
@type init_option() ::
{:strategy, strategy()}
| {:max_restarts, non_neg_integer()}
| {:max_seconds, pos_integer()}
| {:max_children, non_neg_integer() | :infinity}
| {:extra_arguments, [term()]} Параметры, передаваемые функциям start_link и init/1
on_start_child()Source
@type on_start_child() ::
{:ok, pid()}
| {:ok, pid(), info :: term()}
| :ignore
| {:error, {:already_started, pid()} | :max_children | term()} Возвращаемые значения функций start_child
option()Source
@type option() :: GenServer.option()
Параметры, передаваемые функциям start_link
strategy()Source
@type strategy() :: :one_for_one
Поддерживаемые стратегии
sup_flags()Source
@type sup_flags() :: %{
strategy: strategy(),
intensity: non_neg_integer(),
period: pos_integer(),
max_children: non_neg_integer() | :infinity,
extra_arguments: [term()]
} Флаги наблюдателя, возвращаемые при инициализации
Обработчики
init(init_arg)Source
@callback init(init_arg :: term()) :: {:ok, sup_flags()} | :ignore Обработчик, вызываемый для запуска наблюдателя и во время горячих обновлений кода.
Разработчики обычно вызывают DynamicSupervisor.init/1 в конце своего обработчика init, чтобы вернуть соответствующие флаги наблюдения.
Функции
child_spec(opts)Source
Возвращает спецификацию для запуска динамического надзирателя под надзирателем.
См. Supervisor.
count_children(supervisor)Source
@spec count_children(Supervisor.supervisor()) :: %{
specs: non_neg_integer(),
active: non_neg_integer(),
supervisors: non_neg_integer(),
workers: non_neg_integer()
} Возвращает карту, содержащую значения счетчиков для надзирателя.
Карта содержит следующие ключи:
:specs- количество дочерних процессов:active- количество всех активно работающих дочерних процессов, управляемых этим надзирателем:supervisors- количество всех надзирателей, независимо от того, жив ли дочерний процесс:workers- количество всех рабочих процессов, независимо от того, жив ли дочерний процесс
init(options)Source
@spec init([init_option()]) :: {:ok, sup_flags()} Получает набор options, которые инициализируют динамического надзирателя.
Обычно вызывается в конце обратного вызова init/1 модульных надзирателей. Подробнее см. раздел «Модульные надзиратели» в документации по модулю.
options, полученные этой функцией, также поддерживаются функцией start_link/1.
Функция возвращает кортеж с параметрами надзирателя.
Примеры
def init(_arg) do DynamicSupervisor.init(max_children: 1000, strategy: :one_for_one) end
Параметры
:strategy- параметр стратегии перезапуска. Единственное поддерживаемое значение -:one_for_one, что означает, что при завершении дочернего процесса другие дочерние процессы не завершаются. Подробнее о стратегиях можно узнать в документации модуляSupervisor.:max_restarts- максимальное количество перезапусков, разрешённых в заданный промежуток времени. По умолчанию3.:max_seconds- промежуток времени, в течение которого применяется:max_restarts. По умолчанию5.:max_children- максимальное количество дочерних процессов, которые могут работать под этим надзирателем одновременно. При превышении:max_children,start_child/2возвращает{:error, :max_children}. По умолчанию:infinity.:extra_arguments- аргументы, которые добавляются перед аргументами, указанными в спецификации дочернего процесса, передаваемой вstart_child/2. По умолчанию пустой список.
start_child(supervisor, child_spec)Source
@spec start_child(
Supervisor.supervisor(),
Supervisor.child_spec()
| {module(), term()}
| module()
| (old_erlang_child_spec :: :supervisor.child_spec())
) :: on_start_child() Динамически добавляет спецификацию дочернего процесса к supervisor и запускает этот процесс.
child_spec должна быть корректной спецификацией дочернего процесса, как подробно описано в разделе «Спецификация дочернего процесса» в документации Supervisor. Дочерний процесс будет запущен в соответствии с определённой спецификацией.
Если функция запуска дочернего процесса возвращает {:ok, child} или {:ok, child, info}, то спецификация дочернего процесса и PID добавляются к надзирателю, и эта функция возвращает то же самое значение.
Если функция запуска дочернего процесса возвращает :ignore, то ни один дочерний процесс не добавляется в дерево надзора, и эта функция также возвращает :ignore.
Если функция запуска дочернего процесса возвращает ошибку или недопустимое значение или если она завершилась неудачей, спецификация дочернего процесса отбрасывается, а эта функция возвращает {:error, error}, где error — ошибка или недопустимое значение, возвращённое функцией запуска дочернего процесса, или причина сбоя, если произошла ошибка.
Если у надзирателя уже есть N дочерних процессов, при этом N превышает количество :max_children, установленное при инициализации надзирателя (см. init/1), эта функция возвращает {:error, :max_children}.
start_link(options)Source
@spec start_link([option() | init_option()]) :: Supervisor.on_start()
Запускает надзирателя с заданными параметрами.
Параметр :strategy является обязательным и в настоящее время поддерживает значение :one_for_one. Остальные параметры можно найти в документации init/1.
Параметр :name также можно использовать для регистрации имени надзирателя. Поддерживаемые значения описаны в разделе «Регистрация имен» в документации модуля GenServer.
Если надзиратель успешно запущен, эта функция возвращает {:ok, pid}, где pid — PID надзирателя. Если надзирателю задано имя, а процесс с указанным именем уже существует, функция возвращает {:error, {:already_started, pid}}, где pid — PID этого процесса.
Обратите внимание, что надзиратель, запущенный с помощью этой функции, связан с родительским процессом и завершается не только при сбоях, но и если родительский процесс завершается с :normal причиной.
start_link(mod, init_arg, opts \\ [])Source
@spec start_link(module(), term(), [option()]) :: Supervisor.on_start()
Запускает процесс модульного надзирателя с заданным module и arg.
Для запуска надзирателя вызывается обратный вызов init/1 в указанном module, с arg в качестве аргумента. Обратный вызов init/1 должен вернуть спецификацию надзирателя, которая может быть создана с помощью функции init/1.
Если обратный вызов init/1 возвращает :ignore, эта функция также возвращает :ignore и надзиратель завершается с причиной :normal. Если произошел сбой или возвращено некорректное значение, эта функция возвращает {:error, term}, где term — термин с информацией об ошибке, а надзиратель завершается с причиной term.
Параметр :name также можно использовать для регистрации имени надзирателя, поддерживаемые значения описаны в разделе «Регистрация имен» в документации модуля GenServer.
stop(supervisor, reason \\ :normal, timeout \\ :infinity)Source
@spec stop(Supervisor.supervisor(), reason :: term(), timeout()) :: :ok
Синхронно останавливает заданного надзирателя с заданной reason.
Возвращает :ok если надзиратель завершается с указанной причиной. Если он завершается с другой причиной, вызов завершается.
Функция сохраняет семантику OTP относительно отчётов об ошибках. Если причина отличается от :normal, :shutdown или {:shutdown, _}, регистрируется отчёт об ошибке.
terminate_child(supervisor, pid)Source
@spec terminate_child(Supervisor.supervisor(), pid()) :: :ok | {:error, :not_found} Завершает указанного дочернего процесса, идентифицированного по pid.
В случае успеха функция возвращает :ok. Если процесса с указанным PID нет, функция возвращает {:error, :not_found}.
which_children(supervisor)Source
@spec which_children(Supervisor.supervisor()) :: [
{:undefined, pid() | :restarting, :worker | :supervisor,
[module()] | :dynamic}
] Возвращает список с информацией обо всех дочерних процессах.
Обратите внимание, что вызов этой функции при наблюдении за большим количеством дочерних процессов в условиях низкой памяти может привести к исключению из-за нехватки памяти.
Функция возвращает список кортежей, содержащих:
id- всегда:undefinedдля динамических надзирателейchild- PID соответствующего дочернего процесса или атом:restartingесли процесс находится в процессе перезапускаtype-:workerили:supervisorкак определено в спецификации дочернего процессаmodules- как определено в спецификации дочернего процесса
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.13.4/DynamicSupervisor.html