Spec-Zone.ru › Elixir 1.6

DynamicSupervisor поведение

Надзиратель, который запускает потомков динамически.

Модуль Supervisor был разработан для обработки в основном статических потомков, которые запускаются в заданном порядке при запуске надзирателя. DynamicSupervisor запускается без потомков. Вместо этого потомки запускаются по требованию через start_child/2. Когда динамический надзиратель завершается, все потомки завершаются одновременно, без гарантии порядка.

Примеры

Динамический надзиратель запускается без потомков, часто под надзирателем с стратегией надзора (единственная в настоящее время поддерживаемая стратегия — :one_for_one) и именем:

children = [
  {DynamicSupervisor, strategy: :one_for_one, name: MyApp.DynamicSupervisor}
]

Supervisor.start_link(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(sup)
#=> %{active: 2, specs: 2, supervisors: 0, workers: 2}

Надзиратели, основанные на модулях

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

defmodule MyApp.DynamicSupervisor do
  # Automatically defines child_spec/1
  use DynamicSupervisor

  def start_link(arg) do
    DynamicSupervisor.start_link(__MODULE__, arg, name: __MODULE__)
  end

  @impl true
  def init(_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end
end

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

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

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

Миграция из Supervisor’s :simple_one_for_one

В случае использования устаревшей стратегии :simple_one_for_one из модуля Supervisor, вы можете перейти к DynamicSupervisor в несколько шагов.

Представьте данный «старый» код:

defmodule MySupervisor do
  use Supervisor

  def start_link(arg) do
    Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
  end

  def start_child(foo, bar, baz) do
    # This will start child by calling MyWorker.start_link(initial_arg, foo, bar, baz)
    Supervisor.start_child(__MODULE__, [foo, bar, baz])
  end

  @impl true
  def init(initial_arg) do
    children = [
      # Or the deprecated: worker(MyWorker, [initial_arg])
      %{id: MyWorker, start: {MyWorker, :start_link, [initial_arg]})
    ]

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

Его можно обновить для DynamicSupervisor так:

defmodule MySupervisor do
  use DynamicSupervisor

  def start_link(arg) do
    DynamicSupervisor.start_link(__MODULE__, 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(initial_arg) do
    DynamicSupervisor.init(
      strategy: :one_for_one,
      extra_arguments: [initial_arg]
    )
  end
end

Разница в том, что DynamicSupervisor ожидает спецификацию потомка в момент вызова start_child/2, а не во время обратного вызова init. Если при инициализации передаются какие-либо начальные аргументы, например [initial_arg], их можно указать в флаге :extra_arguments в DynamicSupervisor.init/1.

Резюме

Типы

init_option()

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

on_start_child()

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

option()

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

options()

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

strategy()

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

sup_flags()

Флаги надзирателя, возвращаемые при инициализации

Функции

child_spec(arg)

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

count_children(supervisor)

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

init(options)

Получает набор опций для инициализации динамического надзирателя

start_child(supervisor, child_spec)

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

start_link(options)

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

start_link(mod, args, opts \\ [])

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

terminate_child(supervisor, pid)

Завершает заданного потомка, идентифицированного по идентификатору потомка

which_children(supervisor)

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

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

init(args)

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

Типы

init_option()

init_option() ::
  {:strategy, strategy()}
  | {:max_restarts, non_neg_integer()}
  | {:max_seconds, pos_integer()}
  | {:max_children, non_neg_integer() | :infinity}
  | {:extra_arguments, [term()]}

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

on_start_child()

on_start_child() ::
  {:ok, pid()}
  | {:ok, pid(), info :: term()}
  | :ignore
  | {:error, {:already_started, pid()} | :max_children | term()}

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

option()

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

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

options()

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

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

strategy()

strategy() :: :one_for_one

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

sup_flags()

sup_flags() :: %{
  strategy: strategy(),
  intensity: non_neg_integer(),
  period: pos_integer(),
  max_children: non_neg_integer() | :infinity,
  extra_arguments: [term()]
}

Флаги надзирателя, возвращаемые при инициализации

Функции

child_spec(arg)

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

См. Supervisor.

count_children(supervisor)

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)

init([init_option()]) :: {:ok, map()}

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

Этот вызов обычно происходит в конце обратного вызова init/1 надзирателей, основанных на модулях. См. разделы «Надзиратели, основанные на модулях» в документации модуля для получения дополнительной информации.

Опции, получаемые этой функцией, также поддерживаются start_link/2.

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

Примеры

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, :dynamic}. По умолчанию :infinity

  • :extra_arguments - аргументы, которые добавляются перед аргументами, указанными в спецификации потомка, переданной в start_child/2. По умолчанию пустой список.

start_child(supervisor, child_spec)

start_child(
  Supervisor.supervisor(),
  :supervisor.child_spec() | {module(), term()} | module()
) :: on_start_child()

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

child_spec должна быть корректной спецификацией потомка. Процесс потомка будет запущен в соответствии с указанной спецификацией.

Если функция запуска процесса потомка возвращает {:ok, child} или {:ok, child, info}, то спецификация потомка и PID добавляются к надзирателю, и эта функция возвращает то же самое значение.

Если функция запуска процесса потомка возвращает :ignore, то ни один потомок не добавляется в дерево надзора, и эта функция также возвращает :ignore

Если функция запуска процесса потомка возвращает кортеж с ошибкой или ошибочное значение, или если произошла ошибка, спецификация потомка игнорируется, и эта функция возвращает {:error, error}, где error — термин, содержащий информацию об ошибке и спецификации потомка.

Если у надзирателя уже есть N потомков таким образом, что N превышает количество :max_children установленных при инициализации надзирателя (см. init/1), то эта функция возвращает {:error, :max_children}

start_link(options)

start_link(options()) :: 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, args, opts \\ [])

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

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

Для запуска надзорного процесса вызывается обратный вызов init/1 в заданном module, с arg в качестве аргумента. Обратный вызов init/1 должен возвращать спецификацию надзора, которая может быть создана с помощью функции init/1.

Если обратный вызов init/1 возвращает :ignore, эта функция также возвращает :ignore и надзорный процесс завершается с причиной :normal. Если произошла ошибка или возвращено некорректное значение, эта функция возвращает {:error, term}, где term — терм с информацией об ошибке, и надзорный процесс завершается с причиной term.

Опция :name также может быть использована для регистрации имени надзорного процесса, поддерживаемые значения описаны в разделе «Регистрация имени» в документации модуля GenServer.

terminate_child(supervisor, pid)

terminate_child(Supervisor.supervisor(), pid()) :: :ok | {:error, :not_found}

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

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

which_children(supervisor)

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

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

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

Функция возвращает список кортежей, содержащих:

  • id - всегда :undefined для динамических надзорных процессов

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

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

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

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

init(args)

init(args :: term()) :: {:ok, sup_flags()} | :ignore

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

Разработчики обычно вызывают DynamicSupervisor.init/1 в конце своего обратного вызова init для возвращения правильных флагов надзора.

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

Spec-Zone.ru

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