Исходный код 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
The 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/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 обязателен и по умолчанию разрешает максимальное количество перезапусков — 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.
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.17.2/Supervisor.html