Архитектура
Wippy — многослойная система, построенная на Go. Компоненты инициализируются в порядке зависимостей, взаимодействуют через шину событий и выполняют Lua-процессы через планировщик с work-stealing.
Слои
| Слой | Компоненты |
|---|---|
| Приложение | Lua-процессы, функции, воркфлоу |
| Рантайм | Lua-движок (wippyai/go-lua), 40+ модулей |
| Сервисы | HTTP, Queue, Storage, Temporal |
| Система | Topology, Factory, Functions, Contracts |
| Ядро | Scheduler, Registry, Dispatcher, EventBus, Relay |
| Инфраструктура | AppContext, Logger, Transcoder |
Каждый слой зависит только от слоёв ниже него. Слой ядра предоставляет базовые примитивы, а сервисы строят поверх них абстракции более высокого уровня.
Последовательность загрузки
Запуск приложения проходит четыре фазы.
Фаза 1: Инфраструктура
Создаёт базовую инфраструктуру до загрузки каких-либо компонентов:
| Компонент | Назначение |
|---|---|
| AppContext | Запечатываемый словарь ссылок на компоненты |
| EventBus | Pub/sub для взаимодействия между компонентами |
| Transcoder | Сериализация payload (JSON, YAML, Lua) |
| Logger | Структурированное логирование с потоковой передачей событий |
| Relay | Маршрутизация сообщений (Node, Router, Mailbox) |
Фаза 2: Загрузка компонентов
Loader разрешает зависимости топологической сортировкой и загружает компоненты уровень за уровнем, по одному компоненту за раз.
Сначала инициализируются компоненты ядра (PIDGen, Dispatcher, Registry, Finder, Supervisor), затем системные компоненты (Topology, Lifecycle, Factory, Functions, Contracts). Конкретные уровни вычисляются во время выполнения из графа зависимостей, поэтому порядок адаптируется при добавлении или удалении компонентов.
Каждый компонент привязывает себя к контексту во время Load, делая сервисы доступными зависимым компонентам.
Фаза 3: Активация
После загрузки всех компонентов:
- Заморозка Dispatcher - Блокирует реестр обработчиков команд для поиска без блокировок
- Запечатывание AppContext - Запись больше не допускается, включается чтение без блокировок
- Запуск компонентов - Вызывает
Start()у каждого компонента с интерфейсомStarter
Фаза 4: Загрузка записей
Записи реестра (из YAML-файлов) загружаются и валидируются:
- Записи разбираются из файлов проекта
- Этапы конвейера преобразуют записи (override, link, bytecode)
- Сервисы с пометкой
auto_start: trueначинают работу - Супервизор наблюдает за зарегистрированными сервисами
Компоненты
Компоненты — это Go-сервисы, участвующие в жизненном цикле приложения.
Фазы жизненного цикла
| Фаза | Метод | Назначение |
|---|---|---|
| Load | Load(ctx) (ctx, error) |
Инициализация и привязка к контексту |
| Start | Start(ctx) error |
Начало активной работы |
| Stop | Stop(ctx) error |
Корректное завершение |
Компоненты объявляют зависимости. Loader строит направленный ациклический граф и выполняет их в топологическом порядке. Остановка происходит в обратном порядке.
Стандартные компоненты
| Компонент | Зависимости | Назначение |
|---|---|---|
| PIDGen | нет | Генерация ID процессов |
| Dispatcher | нет | Диспатчинг обработчиков команд |
| Registry | Artifact | Хранение и версионирование записей |
| Finder | Registry | Поиск и выборка записей |
| Supervisor | Registry | Политики перезапуска сервисов |
| Topology | нет | Дерево родитель/потомок процессов |
| Lifecycle | Topology | Управление жизненным циклом сервисов |
| Factory | нет | Порождение процессов |
| Functions | Registry | Вызовы функций без состояния |
Шина событий
Асинхронный pub/sub для взаимодействия между компонентами.
Устройство
- Единственная горутина диспатчера обрабатывает все события
- Доставка действий через очередь не блокирует публикаторов
- Сопоставление паттернов поддерживает точные топики и подстановки (
*) - Жизненный цикл на основе контекста привязывает подписки к отмене
Поток событий
sequenceDiagram
participant P as Publisher
participant B as EventBus
participant S as Subscribers
P->>B: Publish(topic, data)
B->>B: Match patterns
B->>S: Queue action
S->>S: Execute callback
Основные топики
Каждое событие несёт System и Kind. Встроенные системы публикуют:
| Система | Kind | Назначение |
|---|---|---|
registry |
entry.create, entry.update, entry.delete, entry.accept, entry.reject |
Изменения записей |
registry |
registry.begin, registry.commit, registry.discard |
Границы транзакций |
process |
factory.register, factory.delete, factory.accept, factory.reject |
Регистрация фабрик для видов процессов |
supervisor |
service.register, service.remove, service.update, service.start, service.stop |
Жизненный цикл сервисов |
Реестр
Версионированное хранилище определений записей.
Возможности
- Версионированное состояние - Каждое изменение создаёт новую версию
- История - По умолчанию история в памяти; опционально история на SQLite для долговременного аудита (history_type: sqlite)
- Событийность - Публикация событий при изменениях
Жизненный цикл записи
flowchart LR
YAML[YAML Files] --> Parser
Parser --> Stages[Pipeline Stages]
Stages --> Registry
Registry --> Validation
Validation --> Active
Этапы конвейера преобразуют записи:
| Этап | Назначение |
|---|---|
| Override | Применение переопределений из конфигурации |
| Disable | Удаление записей по паттерну |
| Link | Разрешение требований и зависимостей |
| Bytecode | Компиляция Lua в байткод |
| EmbedFS | Сбор записей файловой системы |
Relay
Маршрутизация сообщений между процессами на разных узлах.
Трёхуровневая маршрутизация
flowchart LR
subgraph Router
Local[Local Node] --> Peer[Peer Nodes]
Peer --> Inter[Internode]
end
Local -.- L[This node]
Peer -.- P[Registered peer receiver]
Inter -.- I[Other cluster nodes]
- Local - Прямая доставка в пределах одного узла
- Peer - Доставка получателю, зарегистрированному для этого ID узла (внешний пир, например Temporal-воркер)
- Internode - Откат на межузловой транспорт кластера, устанавливаемый компонентом кластера после загрузки
Mailbox
У каждого узла есть mailbox с пулом воркеров:
- Хеширование FNV-1a закрепляет отправителей за воркерами
- Сохраняется порядок сообщений для каждого отправителя
- Воркеры обрабатывают сообщения параллельно
- Back-pressure при заполнении очереди
AppContext
Запечатываемый словарь ссылок на компоненты.
| Свойство | Поведение |
|---|---|
| До запечатывания | Однопоточная запись во время загрузки |
| После запечатывания | Чтение без блокировок, паника при записи |
| Дублирующиеся ключи | Паника |
| Типобезопасность | Типизированные функции-геттеры |
Компоненты привязывают сервисы на фазе Load. После завершения загрузки AppContext запечатывается для оптимальной производительности чтения.
Завершение работы
Корректное завершение происходит в обратном порядке зависимостей:
- SIGINT/SIGTERM запускает завершение
- Супервизор останавливает управляемые сервисы
- Компоненты с интерфейсом
StopperполучаютStop() - Очистка инфраструктуры
Повторный сигнал принудительно завершает процесс немедленно.
См. также
- Планировщик - Выполнение процессов
- Шина событий - Система pub/sub
- Реестр - Управление состоянием
- Диспатчинг команд - Обработка yield'ов