Spec-Zone.ru › Elixir 1.15

Supervisorповедение

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

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

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

Примеры

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

Оговорка

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

defmodule Counter do
  use GenServer

  def start_link(arg) when is_integer(arg) do
    GenServer.start_link(__MODULE__, arg, name: __MODULE__)
  end

  ## Callbacks

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

  @impl true
  def handle_call(:get, _from, counter) do
    {:reply, counter, counter}
  end

  def handle_call({:bump, value}, _from, counter) do
    {:reply, counter, counter + value}
  end
end

Функция Counter получает аргумент в start_link. Этот аргумент передаётся в обратный вызов init/1, который становится начальным значением счётчика. Наш счётчик обрабатывает две операции (известные как вызовы): :get, для получения текущего значения счётчика, и :bump, которая увеличивает счётчик на заданное value значение и возвращает старое значение счётчика.

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

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

# 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 мы регистрируем его с именем Counter с помощью опции name: __MODULE__. Это позволяет нам вызывать его напрямую и получать его значение:

GenServer.call(Counter, :get)
#=> 0

GenServer.call(Counter, {:bump, 3})
#=> 0

GenServer.call(Counter, :get)
#=> 3

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

GenServer.call(Counter, {:bump, "oops"})
** (exit) exited in: GenServer.call(Counter, {:bump, "oops"}, 5000)

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

GenServer.call(Counter, :get)
#=> 0

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

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

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

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

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

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

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

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

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

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

  • :modules — список модулей, используемых механизмами горячей замены кода для определения, какие процессы используют определённые модули. Обычно устанавливается в модуль обратного вызова поведения, таких как GenServer, Supervisor и т. д. Он устанавливается автоматически на основе значения :start и редко изменяется на практике.

  • :significant — логическое значение, указывающее, должен ли дочерний процесс считаться важным с точки зрения автоматического завершения. В качестве значимых можно помечать только :transient и :temporary дочерние процессы. Этот ключ необязателен и по умолчанию равен false. Более подробная информация приведена в разделе «Автоматическое завершение» ниже.

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

Приведённая выше карта определяет дочерний процесс с :id значения Counter, который запускается вызовом Counter.start_link(0).

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

children = [
  {Counter, 0}
]

Затем надзиратель вызовет Counter.child_spec(0) для получения спецификации дочернего процесса. Теперь модуль Counter отвечает за построение собственной спецификации, например, мы могли бы написать:

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

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

use GenServer, restart: :transient

Наконец, также возможно просто передать модуль Counter как дочерний процесс:

children = [
  Counter
]

Когда указано только имя модуля, это эквивалентно вызову {Counter, []}, что в нашем случае было бы некорректным, поэтому мы всегда явно передаём начальный счётчик.

Заменив спецификацию дочернего процесса на {Counter, 0}, мы сохраняем её в модуле Counter. Теперь мы можем поделиться реализацией Counter с другими разработчиками, и они могут добавить её напрямую в своё дерево надзора, не беспокоясь о деталях низкого уровня счётчика.

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

  • карта, представляющая саму спецификацию дочернего процесса — как описано в разделе «Спецификация дочернего процесса»

  • кортеж с модулем в качестве первого элемента и аргументом запуска во втором — например, {Counter, 0}. В этом случае вызывается функция Counter.child_spec(0) для получения спецификации дочернего процесса

  • модуль — например, Counter. В этом случае вызывается Counter.child_spec([]), что некорректно для счётчика, но полезно во многих других случаях, особенно когда вы хотите передать список опций дочернему процессу

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

children = [
  Supervisor.child_spec({Counter, 0}, id: MyCounter, shutdown: 10_000)
]

Стратегии и опции надзирателя

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

children = [
  {Counter, 0}
]

Supervisor.start_link(children, strategy: :one_for_one)

Первый аргумент, переданный в start_link/2, — это список спецификаций дочерних процессов, как определено в разделе «child_spec/1» выше.

Второй аргумент — список опций в ключевом формате.

  • :strategy - опция стратегии наблюдения. Она может быть :one_for_one, :rest_for_one или :one_for_all. Обязательно. Смотрите раздел "Стратегии".

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

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

  • :auto_shutdown - опция автоматического выключения. Она может быть :never, :any_significant, или :all_significant. Необязательно. Смотрите раздел "Автоматическое выключение".

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

Стратегии

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

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

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

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

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

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

Автоматическое выключение

Надзиратели могут автоматически выключаться, когда дочерние процессы, помеченные как :significant, завершают работу.

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

  • :never - это значение по умолчанию, автоматическое выключение отключено.

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

  • :all_significant - когда все значимые дочерние процессы завершат работу, надзиратель автоматически завершит работу своих дочерних процессов, а затем и сам.

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

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

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

Модулеориентированные надзиратели

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

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

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

use Supervisor

Когда вы use Supervisor, модуль Supervisor установит @behaviour Supervisor и определит функцию child_spec/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 в спецификации дочернего процесса, и по умолчанию обычно равна 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}.

Эти завершения также влияют на логирование. По умолчанию такие поведения, как GenServers, не генерируют логи ошибок, когда причиной завершения является :normal, :shutdown или {:shutdown, term}.

Итак, какой код причины завершения следует выбрать? Существует три варианта:

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

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

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

В общем случае, если вы выходите по ожидаемым причинам, вы хотите использовать :shutdown или {:shutdown, term}.

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

Типы

auto_shutdown()

Поддерживаемые параметры автоматического выключения

child()

Дочерний процесс.

child_spec()

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

init_option()

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

name()

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

on_start()

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

on_start_child()

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

option()

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

restart()

Поддерживаемые параметры перезапуска

shutdown()

Поддерживаемые параметры выключения

strategy()

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

sup_flags()

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

supervisor()

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

type()

Тип надзирателя.

Обработчики

init(init_arg)

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

Функции

child_spec(module_or_map, overrides)

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

count_children(supervisor)

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

delete_child(supervisor, child_id)

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

init(children, options)

Получает список спецификаций дочерних процессов для инициализации и набор 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)

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

auto_shutdown()Source

@type auto_shutdown() :: :never | :any_significant | :all_significant

Поддерживаемые параметры автоматического выключения

child()Source

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

Дочерний процесс.

Он может быть PID, когда дочерний процесс был запущен, или :undefined когда дочерний процесс был создан динамическим надзирателем.

child_spec()Source

@type child_spec() :: %{
  :id => atom() | term(),
  :start => {module(), function_name :: atom(), args :: [term()]},
  optional(:restart) => restart(),
  optional(:shutdown) => shutdown(),
  optional(:type) => type(),
  optional(:modules) => [module()] | :dynamic,
  optional(:significant) => boolean()
}

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

Она определяет, как надзиратель должен запускать, останавливать и перезапускать каждый из своих дочерних процессов.

init_option()Source

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

Параметры, передаваемые 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*

restart()Source

@type restart() :: :permanent | :transient | :temporary

Поддерживаемые параметры перезапуска

shutdown()Source

@type shutdown() :: timeout() | :brutal_kill

Поддерживаемые параметры выключения

strategy()Source

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

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

sup_flags()Source

@type sup_flags() :: %{
  strategy: strategy(),
  intensity: non_neg_integer(),
  period: pos_integer(),
  auto_shutdown: auto_shutdown()
}

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

supervisor()Source

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

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

type()Source

@type type() :: :worker | :supervisor

Тип надзирателя.

Является ли надзиратель рабочим процессом или надзирателем.

END_OF_DOCUMENT_MARKER

init(init_arg)Source

@callback init(init_arg :: term()) ::
  {:ok,
   {sup_flags(),
    [child_spec() | (old_erlang_child_spec :: :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, arg}, или спецификацию дочернего процесса.

Если передан кортеж из двух элементов вида {module, arg}, спецификация дочернего процесса извлекается вызовом module.child_spec(arg).

Если передан модуль, спецификация дочернего процесса извлекается вызовом module.child_spec([]).

После извлечения спецификации дочернего процесса, поля 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(
  [
    child_spec()
    | {module(), term()}
    | module()
    | (old_erlang_child_spec :: :supervisor.child_spec())
  ],
  [init_option()]
) ::
  {:ok,
   {sup_flags(),
    [child_spec() | (old_erlang_child_spec :: :supervisor.child_spec())]}}

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

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

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

Примеры

def init(_init_arg) do
  children = [
    {Counter, 0}
  ]

  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.

  • :auto_shutdown — параметр автоматического завершения работы. Может быть :never, :any_significant, или :all_significant

Параметр :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(),
  child_spec()
  | {module(), term()}
  | module()
  | (old_erlang_child_spec :: :supervisor.child_spec())
) :: 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)Source

@spec start_link(
  [
    child_spec()
    | {module(), term()}
    | module()
    | (old_erlang_child_spec :: :supervisor.child_spec())
  ],
  [option() | init_option()]
) ::
  {:ok, pid()}
  | {:error, {:already_started, pid()} | {:shutdown, term()} | term()}
@spec start_link(module(), term()) :: on_start()

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

children — список следующих форм:

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

  • модуль, где module.child_spec([]) будет вызван для извлечения его спецификации дочернего процесса

  • кортеж из двух элементов вида {module, arg}, где module.child_spec(arg) будет вызван для извлечения его спецификации дочернего процесса

Необходимо указать стратегию через параметр :strategy. См. раздел "Стратегии и параметры надзора" для примеров и других параметров.

Параметры также могут быть использованы для регистрации имени надзирателя. Поддерживаемые значения описаны в разделе "Регистрация имени" в документации модуля 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.

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.15.4/Supervisor.html

Spec-Zone.ru

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