Включаемые приложения
Материал из Erlang по-русски.
| Оригинал этой статьи находится по адресу Included Applications |
Перевод: К. Заборский
Дата: 12.11.2006
Версия: 1.0
Содержание |
OTP design principles
Включаемые приложения
Определение
Приложение может включать другие приложения. У включаемого приложения есть свой каталог приложения и .app-файл, но оно запускается как часть дерева надзора другого приложения.
Приложение может быть включено только в одно другое приложение.
Включаемое приложение может включать другие приложения.
Приложение, которое не включено ни в какие другие приложения, называется первичным приложением.
Контроллер приложения автоматически загружает включаемые приложения при загрузке первичного приложения, но не запускает их. Вместо этого супервайзор высшего уровня включаемого приложения должен быть запущен супервайзором приложения, в которое это приложение включено.
Это значит, что при работе включаемое приложение фактически является частью первичного процесса, и процесс во включаемом приложении будет считать себя процессом, принадлежащим первичному приложению.
Указание включаемых приложений
Какие приложения должны быть включены, определяется ключом included_applications в .app-файле.
{application, prim_app,
[{description, "Tree application"},
{vsn, "1"},
{modules, [prim_app_cb, prim_app_sup, prim_app_server]},
{registered, [prim_app_server]},
{included_applications, [incl_app]},
{applications, [kernel, stdlib, sasl]},
{mod, {prim_app_cb,[]}},
{env, [{file, "/usr/local/log"}]}
]}.
Синхронизация процессов при запуске
Дерево надзора включаемого приложения запускается как часть дерева надзора приложения, в которое оно включено. Если есть необходимость в синхронизации между процессами в этих двух приложениях, этого можно добиться при помощи фаз запуска.
Фазы запуска определяются ключом start_phases в .app-файле, в котором содержится список туплов вида {Phase,PhaseArgs}, где переменная Phase - это некоторый атом, а PhaseArgs - терм. Помимо этого, значение ключа mod включающего приложения должно быть выставлено как {application_starter,[Module,StartArgs]}, где Module, как обычно - модуль обратного вызова приложения, а StartArgs - терм, передаваемый функции обратного вызова Module:start/2.
{application, prim_app,
[{description, "Tree application"},
{vsn, "1"},
{modules, [prim_app_cb, prim_app_sup, prim_app_server]},
{registered, [prim_app_server]},
{included_applications, [incl_app]},
{start_phases, [{init,[]}, {go,[]}]},
{applications, [kernel, stdlib, sasl]},
{mod, {application_starter,[prim_app_cb,[]]}},
{env, [{file, "/usr/local/log"}]}
]}.
{application, incl_app,
[{description, "Included application"},
{vsn, "1"},
{modules, [incl_app_cb, incl_app_sup, incl_app_server]},
{registered, []},
{start_phases, [{go,[]}]},
{applications, [kernel, stdlib, sasl]},
{mod, {incl_app_cb,[]}}
]}.
При запуске первичного приложения вместе с включаемыми приложениями, первичное приложение запускается обычным образом: контроллер приложения создаёт владельца приложения, и владелец приложения вызывает Module:start(normal, StartArgs) для запуска супервайзора.
Затем, для первичного приложения и каждого включаемого приложения, в порядке сверху вниз и слева направо, владелец приложения вызывает Module:start_phase(Phase, Type, PhaseArgs) для каждой фазы, определённой для этого приложения и для первичного приложения ???. Заметьте также, что, если фаза не определена для включаемого приложения, функция не будет вызвана для этой фазы и для этого приложения.
Ниже следующие требования предъявляются к .app-файлу включаемого приложения:
- Параметр {mod, {Module,StartArgs}} должен быть указан. Этот параметр используется для нахождения модуля обратного вызова Module для приложения. Переменная StartArgs игнорируется, т.к. функция Module:start/2 вызывается только для первичного приложения.
- Если включаемое приложение само включает приложения, должен быть указан параметр{mod, {application_starter, [Module,StartArgs]}} вместо предыдущего.
- Параметр {start_phases, [{Phase,PhaseArgs}]} должен быть указан, и множество указанных фаз должно быть подмножеством фаз, указанных для первичного приложения.
При запуске prim_app, которое было описано выше, контролллер приложения вызовет следующие функции обратного вызова до того, как application:start(prim_app) вернёт значение:
application:start(prim_app) => prim_app_cb:start(normal, []) => prim_app_cb:start_phase(init, normal, []) => prim_app_cb:start_phase(go, normal, []) => incl_app_cb:start_phase(go, normal, []) ok



