Хост Supervisor

Supervisor — это центральный управляющий хост в экосистеме MorphCluster, построенный на базе фреймворка @morphcluster/core. Он выполняет функции развёртывания, мониторинга и обновления микросервисных пакетов, а также предоставляет служебные сервисы (лицензирование, WebSocket-уведомления, проксирование и др.). Supervisor запускается как самостоятельный процесс Node.js и управляет жизненным циклом дочерних процессов и воркеров, в которых работают другие микросервисы.

Документация описывает внутреннее устройство Supervisor на основе предоставленного исходного кода.

Общая архитектура

Supervisor оформлен как главный модуль, создающий экземпляр ServiceHost и регистрирующий в нём все необходимые сервисы.

Каждый функциональный блок реализован в виде отдельного сервиса, наследующего ServiceRequire (или Service). Сервисы общаются между собой через механизм зависимостей (requirements) и вызовы запросов (sendRequest), а также через глобальные объекты (например, GlobalServices, Config, Logger).

Supervisor управляет пакетами — директориями, содержащими микросервисы (каждый пакет — это самостоятельное приложение, которое может быть запущено как отдельный процесс или воркер). Пакеты могут быть двух типов:

Сам Supervisor тоже является пакетом и может обновлять сам себя.

Точка входа и инициализация

Файл src/start.mjs выполняет следующие шаги:

  1. Создаёт экземпляр ServiceHost с именем "Supervisor".
  2. Загружает конфигурацию (Config) из config.mjs и сохраняет в host.Config.
  3. Настраивает корневой логгер Logger:
    • Читает параметры из config.values.Logger.
    • Добавляет бэкенды: LoggerBackendConsole и LoggerBackendStore (отправка логов в централизованное хранилище).
  4. Регистрирует глобальный обработчик uncaughtException.
  5. Последовательно добавляет все системные и пользовательские сервисы при помощи функции addService(svcName, svcClass). Каждый сервис получает конфигурацию, объединяющую config.values[svcName] и config.values.common.
  6. Запускает хост: host.start(log).
  7. После успешного старта выводит "***All Services Started***".
  8. Регистрирует обработчики сигналов SIGINT и SIGTERM, а также сообщения shutdown для воркеров, которые вызывают функцию stop().

Функция stop() вызывает host.stop(), после чего завершает процесс с заданным кодом (по умолчанию 0). Таймаут принудительного завершения — 60 секунд.

Список системных сервисов, добавляемых в хост:

Имя в хосте Класс / Назначение
PostgresMigrator Миграция схем БД PostgreSQL
LogStoreBackend, LogStoreAdmin, LogOraList Сервисы логирования (из @morphcluster/logger)
NatsTimersPublisher, NatsTimersAggregator Мониторинг таймеров через NATS
License Проверка и управление лицензией
Sessions, Auth Хранение сессий и аутентификация
Registry (Dummy), CommonRegistry, RegistryHelper Централизованное хранилище настроек
GlobalServices Реестр глобальных сервисов
HttpProxy, FastifyGateway, ServiceBridge HTTP-инфраструктура
NatsConnection, NatsRequestListener, NatsEventPublisher, NatsSchemaPublisher, NatsSchemaListener, NatsHealthPublisher, NatsHealthSubscriber, NatsConnectionTest Подключение и маршрутизация через NATS
Eventer WebSocket-сервер для real-time уведомлений
PackageInfo, NodeHosts, Packages, PkgExtractor, PkgUpdater, PkgCleanup Управление пакетами (см. ниже)

Основные сервисы

PackageInfo

Файл: src/PackageInfo/index.js

Хранит информацию об установленных пакетах в JSON-файле package-infos.json в директории данных (dataDir). Каждая запись содержит имя пакета, источник установки, признак ручного управления и дату установки.

Запросы:

Зависимости: нет (кроме базового ServiceRequire). Используется другими сервисами для отслеживания статуса установки.

NodeHosts

Файл: src/NodeHosts/index.js

Управляет запущенными экземплярами пакетов — процессами и воркерами. Хранит массив объектов ProcessMaster или WorkerMaster.

Запросы:

При запуске startHost проверяет, запущен ли уже хост с таким ID. Если нет — создаёт экземпляр ProcessMaster или WorkerMaster в зависимости от флага isWorker, устанавливает переменные окружения (MCL_CONFIG, MCL_DATA_DIR, TZ) и запускает.

Зависимости: нет (базовый сервис).

Packages

Файл: src/Packages/index.js

Центральный сервис управления жизненным циклом пакетов. Отвечает за:

Запросы:

Методы жизненного цикла:

Зависимости: PackageInfo, NodeHosts.

PkgExtractor

Файл: src/PkgExtractor/index.js

Распаковывает архивы .7z с пакетами, находящиеся в dataDir/pkg-install, в директорию пакетов.

Запросы:

Использует библиотеку node-7z для распаковки.

Зависимости: Packages, PackageInfo.

PkgUpdater

Файл: src/PkgUpdater/index.js

Сервис автоматического обновления пакетов с удалённого сервера обновлений. Работает по таймеру, настраиваемому через CommonRegistry.

Запросы:

Зависимости: Packages, PackageInfo, PkgExtractor, RegistryHelper.

Конфигурация в CommonRegistry (схема registry-schema.js):

PkgCleanup

Файл: src/PkgCleanup/index.js

Сервис автоматической очистки устаревших пакетов (не запущенных и не помеченных как ручные, установленных через обновление). Периодичность задаётся в CommonRegistry, но в текущей реализации таймер закомментирован, очистка выполняется только при ручном вызове cleanup.

Запросы:

Зависимости: Packages, PackageInfo, RegistryHelper.

Eventer

Файл: src/Eventer/index.mjs

Реализует WebSocket-сервер для доставки real-time сообщений подключённым пользователям. Работает поверх библиотеки ws.

Запросы:

События:

Аутентификация: клиент после подключения должен отправить сообщение {"type":"auth","token":"..."}. Токен проверяется через сервис Sessions. После успешной аутентификации клиент может подписаться на каналы сообщением {"type":"subscribe","channel":"..."}. Внутренний класс Connection управляет состоянием одного WebSocket-соединения.

Сервер запускается на выделенном порту (или 0, тогда назначается случайный), регистрируется в HttpProxy как WebSocket-прокси по префиксу prefixUrl (по умолчанию /eventer).

Периодически (каждые pingTimeout мс) проверяет живучесть соединений с помощью ping/pong.

Зависимости: Sessions.

License

Файл: src/License/index.mjs

Управляет файлом лицензии (license.json). Содержит поля name, expire, key (зашифрован). Периодически (каждые 60 секунд) проверяет изменение лицензии и генерирует событие onLicenseChanged.

Запросы:

Зависимости: нет.

Вспомогательные классы управления процессами

Находятся в src/lib/. Иерархия: BaseMasterProcessMaster, WorkerMaster.

BaseMaster

Абстрактный класс, реализующий общую логику управления запущенным процессом или воркером:

ProcessMaster

Наследует BaseMaster. Запускает дочерний процесс через child_process.spawn. Передаёт переменные окружения, рабочую директорию. При stop() отправляет SIGTERM, при terminate()SIGKILL.

WorkerMaster

Наследует BaseMaster. Запускает worker thread (worker_threads.Worker). Поддерживает передачу сообщений через postMessage. При _sendStop() отправляет сообщение { type: 'shutdown' } в воркер. При terminate() вызывает worker.terminate().

Взаимодействие с инфраструктурой MorphCluster

Supervisor активно использует следующие компоненты MorphCluster:

Жизненный цикл пакетов

  1. Установка — архив .7z помещается в dataDir/pkg-install. PkgExtractor распаковывает его в packagesDir, создавая директорию с именем <name>-<version>. В PackageInfo добавляется запись об установке.
  2. Первый запуск — Packages сканирует директории, при отсутствии автозапуска запускает все дистрибутивные пакеты.
  3. Автозапуск — список ID пакетов сохраняется в packages-autostart.json. При старте Supervisor запускает все пакеты из этого списка.
  4. Обновление — PkgUpdater периодически опрашивает сервер обновлений, скачивает новые версии, устанавливает их рядом со старыми. При запуске новой версии старая останавливается, а после успешного старта — удаляется (если не помечена как manual).
  5. Ручное управление — если пакет помечен manual: true, он не будет автоматически остановлен или удалён при обновлении. Пользователь сам управляет его запуском.
  6. Очистка — PkgCleanup удаляет неиспользуемые автоустановленные пакеты.

Конфигурация

Файл src/config.mjs содержит значения по умолчанию, которые могут быть переопределены через внешний файл конфигурации (Config.load()). Основные параметры:

Процесс остановки

  1. При получении сигнала или вызове HostStopper.stop() запускается stop() в start.mjs.
  2. Устанавливается 60-секундный таймаут, после которого процесс будет принудительно завершён, а список незавершённых сервисов выведен в консоль.
  3. Вызывается host.stop(), который последовательно останавливает все сервисы (каждый сервис вызывает остановку своих процессов/воркеров через NodeHosts).
  4. После успешной остановки процесс завершается с заданным кодом.

HostStopper — глобальный синглтон, позволяющий другим сервисам (например, Packages.restartSupervisor) инициировать остановку всего хоста с определённым кодом (85 для перезапуска supervisor).


Revision #1
Created 21 June 2026 20:27:40 by Admin
Updated 26 June 2026 15:00:34 by Admin