Исходный код Надзиратель поведение
Модуль поведения для реализации надсмотрщиков.
Надсмотрщик — это процесс, который контролирует другие процессы, которые мы называем дочерними процессами. Надсмотрщики используются для построения иерархической структуры процессов, называемой деревом надзора. Деревья надзора обеспечивают отказоустойчивость и описывают, как запускаются и завершаются наши приложения.
Надсмотрщик можно запустить напрямую со списком спецификаций дочерних процессов с помощью 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
Затем надсмотрщик вызовет 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/1.- 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)
Возвращает список с информацией обо всех дочерних процессах данного диспетчера.
Типы
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/1.
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 в конце своего обработчика инициализации, чтобы вернуть правильные флаги супервайзера.
Функции
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 обязательна и по умолчанию разрешает максимальное количество перезапусков в течение 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 должна быть допустимой спецификацией дочернего процесса. Запуск дочернего процесса будет производиться согласно спецификации.
Если спецификация дочернего процесса с указанным ID уже существует, 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.
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-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/Supervisor.html