новости сообщество форум вики
Статья   Обсуждение   Править   История  

MAN Страницы/supervisor


 

supervisor 3

stdlib 1.14.3
Ericsson AB
ERLANG MODULE DEFINITION

МОДУЛЬ

supervisor - Поведение реализующее основы супервизора

ОПИСАНИЕ



Модуль поведения необходимого для реализации супервизора - процесс контролирующий другие процессы, называемые дочерними процессами. Дочерний процесс может быть как другим супервизором, так и процессом-рабочим. Рабочий обычно реализуется при помощи одного из gen_event, gen_fsm, или gen_server поведений. Супервизор реализованный при помощи этого модуля обладает набором стандартных интерфейсных функций и включает возможность обнаружения и отслеживания ошибок. Супервизоры используются для построения иерархичной структуры, называемой деревом контроля - эффективного способа создания устойчивого к ошибкам приложения. Обратитесь к "Принципам структуры OTP" ("Принципы программирования на OTP"? "Принципы построения OTP"?) (OTP Design Principles) для детальной информации.

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

Если не определенно другого, все функции в этом модуле будут завершатся с ошибкой (умирать? вылетать? ошибочно завершатся? fails) если указанный процесс-супервизор не существует или переданы неправильные данные.

Принципы Контроля



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

Дочерний процесс супервизора определяется при помощи списка спецификаций дочерних процессов (child specifications). Когда супервизор запускается, дочерние процессы запускаются в порядке расположения (слева направо) в этом списке. При завершении же супервизора сначала завершаются все дочерние процессы в обратном запуску порядке, т.е. справа налево.



Супервизор может обладать одной из двух политик перезапусков:

  • one_for_one - когда один дочерний процесс завершается и должен быть перезапущен\&, перезапуск затрагивает только этот процесс.
  • one_for_all - когда один дочерний процесс завершается и должен быть перезапущен\&, все остальные дочерние процессы также завершаются, после чего все процессы запускаются заного.
  • rest_for_one - когда один дочерний процесс завершается и должен быть перезапущен\&, оставшиеся после его завершения дочерние процессы также завершаются в том же порядке в каком и запускались. После чего запускается завершившийся дочерний процесс, а после него все остальные.
  • simple_one_for_one - упрощенный вариант политики one_for_one, когда все дочерние процессы - динамически добавляемые процессы одного типа, т.е. имеющие одинаковый код.




Функции terminate_child/2, delete_child/2 и restart_child/2 неприемлимы при использовании simple_one_for_one политики и будут возвращать кортеж {error, simple_one_for_one} в случае если заданный супервизор использует эту политику перезапусков.


Для предотвращения попадания супервизора в бесконечный цикл завершений и перезапусков дочерних процессов, существует понятие максимальной частоты перезапусков, определяемое при помощи двух целочисленых значений MaxR и MaxT. Если произошло больше чем MaxR перезапусков за период MaxT секунд, супервизор завершает все свои дочерние процессы, после чего завершается сам.



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

child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
Id = term()
StartFunc = {M,F,A}
M = F = atom()
A = [term()]
Restart = permanent | transient | temporary
Shutdown = brutal_kill | int()>=0 | infinity
Type = worker | supervisor
Modules = [Module] | dynamic
Module = atom()
  • Id - это имя которое используется для обозначения спецификации внутри супервизора.
  • Переменная StartFunc определяет стартовую функцию запускающую дочерний процесс. Она должна быть представленна в виде кортежа "модуль-функция-аргументы" {M, F, A} используемом как apply(M, F, A).





Стартовая функция должна создать дочерний процесс, установить с ним связь, и вернуть кортеж {ok, Child} или {ok, Child, Info}, где Child - идентификатор дочернего процесса, а Info - произвольный терм, который игнорируется супервизором.




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




Если же произошла какая либо ошибка, функция может вернуть кортеж {error, Error}.




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

  • Переменная Restart определяет в каком случае завершившийся дочерний процесс должен быть перезапущен. Если значение равняется permanent, то он должен перезапускаться всегда; в случае значения temporary процесс не будет будет перезапущен ни при каких условиях, а в случае transient дочерний процесс будет завершен только при ненормальном завершении процесса, т.е. при завершении с причиной отличной от normal.
  • Переменная Shutdown определяет как именно дочерний процесс должен быть завершен (политику завершений). Значение brutal_kill означает, что дочерний процесс будет безоговорочно уничтожен с использованием функции exit(Child, kill). Целочисленное же значение таймаута обозначает, что супервизор пошлет дочернему процессу сигнал на завершение используя функцию exit(Child, shutdown), после чего будет ожидать от дочернего процесса сигнала о завершении с причиной shutdown. Если же в течении заданного таймаутом промежутка времени такого сигнала не поступит, процес будет безоговорочно унитожен с применением функции exit(Child, kill).




В случае, если дочерний процесс является супервизором, значение Shutdown должно равнятся infinity, чтобы дать время на завершение всему поддереву.





Важное замечание насчет супервизовров с политикой перезапусков "simple-one-for-one" (так называемые simple-one-for-one супервизоры): Динамически создаваемые дочерние процессы simple-one-for-one супервизоров не завершаются автоматически, в независимости от политики завершений, но ожидается, что они должны быть все завершены к моменту завершения процесса супервизора (к моменту прихода сигнала на завершение от родительского супервизору процесса).



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

  • Переменная Type обозначает является ли дочерний процесс супервизором или же рабочим.
  • Переменная Modules используется в обработчике обновлений во время динамической подмены кода, для точного определения конкретных модулей используемыъ данным процессом. На практике (в основном? rule of thumb) переменная Modules должна быть списком из одного элемента - [Module], где Module это используемый процессом callback-модуль, в случае если дочерний процесс является супервизором, gen_server процессом или gen_fsm процессом, а если же дочерний процесс является обработчиком событий (gen_event процесс) с динамическим набором callback-модулей, переменная Modules должна равнятся dynamic. Обратитесь к "Принципам структуры OTP" ("Принципы программирования на OTP"? "Принципы построения OTP"?) (OTP Design Principles) для детальной информации.


  • Также супервизор внутри себя хранит запись об идентификаторе дочернего процесса Child, или же undefined если процесса не существует.
  • ЭКСПОРТ



    start_link(Module, Args) -> Result


start_link(SupName, Module, Args) -> Result
Типы

SupName = {local, Name} | {global, Name}
aName = atom()
Module = atom()
Args = term()
Result = {ok, Pid} | ignore | {error, Error}
аPid = pid()
аError = {already_started, Pid}} | shutdown | term()




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



Созданный супервизор вызывает callback-функцию Module:init/1 для получения данных о стратегии перезапусков, максимальной частоте перезапусков и дочерних процессах. В целях синхронизации процедуры запуска, функция start_link/2, 3 не возвращает управление до тех пор пока не завершится callback-функция Module:init/1 и не будут запушены все дочерние процессы.

В случае если SupName={local, Name} супервизор будет зарегистрирован локально как Name с использованием функции register/2. Если же SupName={global, Name} супервизор будет зарегистрирован глобально под именем Name и global:register_name/2. Если никакого имени SupName не предоставленно, то супервизор не будет зарегистрирован.

Module - имя callback-модуля.

Args - произвольный терм, который передается в качестве аргумента в callback-функцию Module:init/1.

В случае если супервизор и все его дочерние процессы успешно созданы (т.е. все стартовые функции дочених процессов вернули {ok, Child}, {ok, Child, Info}, или ignore) функция возвращает {ok, Pid}, где Pid - идентификатор процесса супервизора. В случае если процесс с заданным SupName уже существует, то функция вернет {error, {already_started, Pid}}, где Pid - идентификатор этого процесса.

В случае если callback-функция Module:init/1 вернет ignore, эта функция также вернет ignore и супервизор завершится с причиной normal. В случае если callback-функция Module:init/1 дает сбой (умирает? завершается с ошибкой? fails) или же возвращает неверное значение, эта функция возвращает {error, Term}, где Term - терм с информацией об ошибке, и супервизор завершается с причиной Term.

Если какая-либо из стартовых функций дочерних процессов дает сбой (умирает? завершается с ошибкой? fails) или возвращает сообщение об ошибке или же неправильное значение, функция вернет {error, shutdown} и супервизор завершит все запущенные дочерние процессы, после чего завершится сам с причиной shutdown.



start_child(SupRef, ChildSpec) -> Result
Типы

SupRef = Name | {Name, Node} | {global, Name} | pid()
аName = Node = atom()
ChildSpec = child_spec() | [term()]
Result = {ok, Child} | {ok, Child, Info} | {error, Error}
аChild = pid() | undefined
аInfo = term()
аError = already_present | {already_started, Child} | term()




Передает спецификацию дочернего процесса супервизору SupRef, который динамически добавляет её в список спецификаций дочернего процесса, запуская соответствующий спецификации дочерний процесс.



SupRef может быть:

  • Идентификатором процесса,
  • Атомом Name, в случае если супервизор локально зарегистрирован под этим именем,
  • Кортежем {Name, Node}, в случае если супервизор локально зарегистрирован под именем Name на другом узле, или же
  • Кортежем {global, Name}, в случае если супервизор зарегистрирован глобально под именем Name.


Терм ChildSpec должен быть действительной спецификацей дочернего процесса (кроме случая когда уелевой супервизор является simple_one_for_one супервизором, такой вариант описан ниже). Дочерний процесс будет запущен при помощи стартовой функции, указанной в спецификации.

В случае simple_one_for_one супервизора, будет использована спецификация дочернего процесса определенная в callback-функции Module:init/1 и терм ChildSpec должен быть произвольным списком List. Дочерний процесс будет запущен при помощи стартовой функции с добавленными аргументами из списка List, т.е. при помощи вызова функции apply(M, F, A++List), где {M, F, A} - стартовая функция определенная в спецификации дочернего процесса.



Если же спецификация с такими же Id и ChildSpec уже присутствует в супервизоре, то она игнорируется и функция возвращает {error, already_present} или {error, {already_started, Child}}, в зависимости от того, работает ли соответствующий спецификации дочерний процесс или нет.

В случае когда стартующая функция дочернего процесса возвращает {ok, Child} или {ok, Child, Info}, спецификация и идентификатор дочернего процесса запоминаются супервизором и эта функция возвращает тоже самое.

Если же стартовая функция возвращает ignore, то спецификция запоминается супервизором, а в качестве идентификатора дочернего процесса запоминается атом undefined, и эта функция возвращает кортеж {ok, undefined}.

А если стартовая функция возвращает кортеж с информацией об ошибке или неверное значение, или же просто дает сбой (умирает? вылетает? fails), эта спецификация дочернего процесса игнорируется и функция возвращает кортеж {error, Error}, где Error - терм содержащий информацию о произошедшей ошибке и спецификации ее вызвавшей, т.е. об этой спецификации.



terminate_child(SupRef, Id) -> Result
Типы

SupRef = Name | {Name, Node} | {global, Name} | pid()
аName = Node = atom()
Id = term()
Result = ok | {error, Error}
аError = not_found | simple_one_for_one




Приказывает супервизору SupRef завершить дочерний процесс соответствующий спецификации, которая, в свою очередь, определяется по переданному идентификатору Id. Этот процесс, если он присутствует, завершается, но его спецификация остается в супервизоре. Это означает, что впоследствии этот процесс может быть перезапущен супервизором. Также этот дочерний процесс может быть перезапущен и вручную при помощи функции restart_child/2. Для удаления оставшейся спецификации можно использовать функции delete_child/2.



Обратитесь к start_child/2 за подробным описанием аргумента SupRef.

В случае успеха функция возвращает ok в противном же случае - если спецификации с таким идентификатором Id не существует - функция возвращает {error, not_found}.



delete_child(SupRef, Id) -> Result
Типы

SupRef = Name | {Name, Node} | {global, Name} | pid()
аName = Node = atom()
Id = term()
Result = ok | {error, Error}
аError = running | not_found | simple_one_for_one




Приказывает супервизору SupRef удалить спецификацию дочернего процесса с идентификатором Id. Соответствующий ей процесс должен быть предварительно завершен, для чего необходимо использовать функцию terminate_child/2.



Обратитесь к start_child/2 за подробным описанием аргумента SupRef.

В случае успеха, функция возвращает ok. В случае когда спецификая с идентификатором Id сцществует, но дочерний процесс, соответствующий ей, работает, функция вернет кортеж{error, running}. Если жи спецификации с таким идентификатором Id вообще не существует, то эта функция вернет {error, not_found}.



restart_child(SupRef, Id) -> Result
Типы

SupRef = Name | {Name, Node} | {global, Name} | pid()
аName = Node = atom()
Id = term()
Result = {ok, Child} | {ok, Child, Info} | {error, Error}
аChild = pid() | undefined
аError = running | not_found | simple_one_for_one | term()




Приказывает супервизору SupRef перезапустить дочерний процесс соответствующий спецификации с идентификатором Id. Эта спецификация должна существовать и процесс соответствующий ей не должен работать (не должен быть запущен?).



Обратитесь к start_child/2 за подробным описанием аргумента SupRef.

Если спецификации с идентификатором Id не существует, то функция вернет кортеж {error, not_found}. А если же такая спецификация существует, но соответсвующий ей дочерний процесс работает, функция вернет кортеж {error, running}.

Если стартовая функция дочернего процесса возвращает {ok, Child} или {ok, Child, Info}, идентификатор этого процесса запоминается супервизором и функция возвращет такое же значение.

Если же стартовая функция возвращает ignore, идентификатор дочернего процесса остается равным атому undefined и функция возвращает {ok, undefined}.

А в случае когда стартовая функция дочернего процесса возвращает кортеж с ошибкой, неверное значение или же дает сбой (умирает? вылетает? дохнет? fails), функция возвращает {error, Error}, где Error - терм содержащий информацию о произошедшей ошибке.



which_children(SupRef) -> [{Id,Child,Type,Modules}]
Типы

SupRef = Name | {Name, Node} | {global, Name} | pid()
аName = Node = atom()
Id = term() | undefined
Child = pid() | undefined
Type = worker | supervisor
Modules = [Module] | dynamic
аModule = atom()




Возвращает список данных о всех спецификациях и дочерних процессах супервизора SupRef.



Обратитесь к start_child/2 за подробным описанием аргумента SupRef.

Информация выдаваемая по каждой спецификации/дочернему процессу созтоит из:

  • Терма Id - такого же как и в спецификации или же равного атому undefined в случае simple_one_for_one супервизора.
  • Child - идентификатора соответствующего дочернего процесса, или же атома undefined если таковой процесс отсутствует.
  • Атома Type взятого из спецификации.
  • Списка Modules взятого из спецификации.


check_childspecs([ChildSpec]) -> Result
Типы

ChildSpec = child_spec()
Result = ok | {error, Error}
аError = term()




Эта функция принимает в качестве аргумента список спецификаций дочерних процессов и возвращает атом ok если все они корректно составлены, или же кортеж {error, Error} в противном случае.

CALLBACK\-ФУНКЦИИ



Представленные функции должны быть экспортированы из callback-модуля для поведения supervisor.

ЭКСПОРТ



Module:init(Args) -> Result


Типы

Args = term()
Result = {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}} | ignore
аRestartStrategy = one_for_all | one_for_one | rest_for_one | simple_one_for_one
аMaxR = MaxT = int()>=0
аChildSpec = child_spec()




В случае если супервизор запущен при помощи функции supervisor:start_link/2, 3, эта функция вызывается созданным процессом для определения политики и максимальной частоты перезапусков, а также для получения списка спецификаций дочерних процессов.



Args - аргумент Args передаваемый вызывающей функции.

RestartStrategy - стратегия перезапусков и значения MaxR и MaxT, определяющие максимаьную частоту оных. [ChildSpec] это список спецификаций определяющих какие дочерние процессы супервизор должен запустить и отслеживать. Обратитесь к описанию Принципов Контроля выше.

Стоит отметить, что в случае стратегии перезапусков simple_one_for_one, список спецификаций дочерних процессов должен быть спиком из только одной спецификации, параметр Id которой игнорируется. Также, во время инициализации, не происходит запуска дочерних процессов, так как предпологается, что все необходимые процессы будут запущены динамически при помощи функции supervisor:start_child/2.

Функция также может вернуть атом ignore.

ВНИМАНИЕ!



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

СВЯЗАННАЯ ДОКУМЕНТАЦИЯ



gen_event(3), gen_fsm(3), gen_server(3), sys(3)

АВТОР

Gunilla Arendt - support@erlang.ericsson.se

ПЕРЕВОД

Полежаев "Night Nord" Петр - NightNord@gmail.com
 

так же

Личные инструменты
Представиться системе



 

 

Навигация

документация

внешние ссылки

друзья

прочее

Инструменты