Spec-Zone.ru › Elixir 1.18

Источник 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 позволяет передавать кортеж с именем модуля и аргументом запуска вместо спецификации:

children = [
  {Counter, 0}
]

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

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

Затем надзиратель вызовет Counter.start_link(arg) для запуска дочернего процесса. Этот поток обобщен на диаграмме ниже. Вызывающий процесс создает надзирающий процесс. Надзиратель затем обращается к вашему коду (модуль) для запуска дочернего процесса:

sequenceDiagram
    participant C as Caller (Process)
    participant S as Supervisor (Process)
    participant M as Module (Code)

    note right of C: child is a {module, arg} specification
    C->>+S: Supervisor.start_link([child])
    S-->>+M: module.child_spec(arg)
    M-->>-S: %{id: term, start: {module, :start_link, [arg]}}
    S-->>+M: module.start_link(arg)
    M->>M: Spawns child process (child_pid)
    M-->>-S: {:ok, child_pid} | :ignore | {:error, reason}
    S->>-C: {:ok, supervisor_pid} | {:error, reason}

К счастью для нас, 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.

module_spec()

Спецификация дочернего процесса на основе модуля.

name()

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

on_start()

Возвращаемые значения start_link/2 и start_link/3.

on_start_child()

Возвращаемые значения start_child/2.

option()

Значения параметров, используемые функциями start_link/2 и start_link/3.

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)

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

END_OF_DOCUMENT_MARKER

Типы

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.

module_spec()Source

@type module_spec() :: {module(), args :: term()} | module()

Спецификация процесса-потомка, основанная на модуле.

Это форма спецификации процесса-потомка, которую вы можете передать таким функциям, как child_spec/2, start_child/2 и start_link/2, помимо нормализованной child_spec/0.

Спецификация процесса-потомка, основанная на модуле, может быть:

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

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

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/2 и start_link/3.

on_start_child()Source

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

Возвращаемые значения start_child/2.

option()Source

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

Значения параметров, используемые функциями start_link/2 и start_link/3.

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

Тип управляемого потомка.

Рабочий или супервайзер.

Обработчики

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_spec(),
  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_spec()
    | (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_spec()
  | (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_spec()
    | (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 — список следующих форм:

  • спецификация дочернего процесса (см. child_spec/0)

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

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

  • спецификация дочернего процесса в стиле Erlang (старый стиль) (см. :supervisor.child_spec())

Стратегия должна быть указана через параметр :strategy. См. «Стратегии и параметры надсмотрщика» для примеров и других параметров.

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

Если надсмотрщик и все дочерние процессы успешно запущены (если функция запуска каждого дочернего процесса возвращает {:ok, child}, {:ok, child, info}, или :ignore), функция возвращает {:ok, pid}, где pid — PID надсмотрщика. Если надсмотрщику задано имя, и процесс с указанным именем уже существует, функция возвращает {:error, {:already_started, pid}}, где pid — PID этого процесса.

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

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

END_OF_DOCUMENT_MARKER

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, _}, будет записан отчёт об ошибке.

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

Загрузить версию ePub

Создано с помощью ExDoc (v0.36.1) для язык программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/Supervisor.html

Spec-Zone.ru

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