graph TD
%% Определение стилей компонентов (В строгом соответствии с вашим главным шаблоном)
classDef transport fill:#E3F2FD,stroke:#0D47A1,stroke-width:1px;
classDef coreEngine fill:#FFF9C4,stroke:#FBC02D,stroke-width:1px;
classDef storage fill:#D9EAD3,stroke:#274E13,stroke-width:2px;
classDef external fill:#F3E5F5,stroke:#7E57C2,stroke-width:1px;
%% 1. Транспортный слой (Входной контур)
subgraph Transport_Layer ["1. Edge & Transport Layer - Управление"]
Client["HTTP API Клиент / UI"]:::transport
Ctrl["EngineController - Start / Stop Handlers"]:::transport
end
%% 2. Ядро Симулятора (Контур Оркестрации)
subgraph Core_Layer ["2. Simulation Core Layer - Ядро Движка"]
Engine["SimulationEngine - Loop Core"]:::coreEngine
Loader["DBProfileLoader - Interface Assertion"]:::coreEngine
Tick["Virtual Time Clock - +1 Hour step loop"]:::coreEngine
Pool["Worker Pool - Bounded Concurrency Semaphore"]:::coreEngine
Plugin["Business Process Plugin - Advance & Evaluate"]:::coreEngine
end
%% 3. Слой Хранения и Очередей (Выходной контур)
subgraph Storage_Layer ["3. Storage & Persistence Layer - Слой данных"]
Postgres["PostgreSQL DB - Static User Profiles"]:::storage
Redis["Redis Session Cache - State Hydration DB 0"]:::storage
subgraph Kafka_Cluster ["Apache Kafka Cluster - Шина событий"]
T_Hist["topic: twin-history-events"]:::storage
T_Intent["topic: agent-intents"]:::storage
end
end
%% 4. Внешние Зависимости
subgraph External_Layer ["4. External Domain Services"]
DomainAPI["gRPC Downstream Services - Login / GetFridgeState"]:::external
end
%% Направления основных потоков данных
Client -->|POST /start или POST /stop| Ctrl
Ctrl -->|1. Динамическое приведение| Loader
Loader -->|2. Bulk Query profiles| Postgres
Ctrl -->|3. Асинхронный запуск в бэкграунд| Engine
Engine -->|4. Инициация цикла| Tick
Tick -->|5. Распараллеливание Fan-Out| Pool
%% Логика работы Bounded Concurrency воркеров внутри семафора
Pool -->|6. Проверка стейта / Cache Miss| Redis
Redis -.->|7. Fallback: StateWarmer| DomainAPI
DomainAPI -.->|8. Сохранить прогретый стейт| Redis
Pool -->|9. Вычисление мат-модели| Plugin
%% Выходные топики Kafka
Plugin -->|10a. Каждый тик: Снимок параметров| T_Hist
Plugin -->|10b. Интенты отличные от IDLE| T_Intent
SIM: Движок цифрового симулятора (Simulation Engine)
В открытом доступе представлена демонстрационная версия метода. В настоящей публичной документации отображены не все шаги, технические сценарии и приватные эндпоинты для системы цифровых симуляторов бизнес-процессов.
- Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).
1. Концепция Движка (Simulation Engine)
Движок симулятора — это изолированный архитектурный компонент (микросервис на языке Go), который обеспечивает жизненный цикл симуляции, оркестрацию потоков времени, управление конкурентностью, интеграцию с базами данных и шинами сообщений.
Движок спроектирован по принципу Pluggable Architecture (подключаемые модули). Он ничего не знает о специфике бизнес-логики (будь то кухня, логистика или финансы) и оперирует абстрактными интерфейсами процессов.
Схема архитектуры компонента (Simulation Engine Architecture)
Ниже представлена детальная схема внутренней архитектуры и внешних интеграционных потоков движка симулятора. Компонент объединяет синхронный контур управления (HTTP REST), асинхронный контур параллельного выполнения (Fan-Out Goroutines Pool) и слои кэширования и брокеров сообщений.
Схема архитектуры компонента (Simulation Engine Architecture)
Ниже представлена детальная схема внутренней архитектуры и внешних интеграционных потоков движка симулятора. Компонент объединяет синхронный контур управления (HTTP REST), асинхронный контур параллельного выполнения (Fan-Out Goroutines Pool) и слои кэширования и брокеров сообщений.
Общая топология системы:
2. API Управление и Жизненный цикл Симуляции
Управление симуляциями осуществляется через EngineController посредством HTTP REST API. Контроллер обеспечивает неблокирующий запуск и безопасную принудительную остановку процессов.
2.1 Асинхронный запуск (StartHandler)
При получении запроса POST /start движок выполняет следующие шаги:
Декодирование и валидация: Извлекается
ProcessID,ProcessTypeи глубина симуляции в часах (Hours).Динамическое извлечение возможностей (Interface Assertion): Движок берет абстрактный процесс из реестра (
processRegistry) и приводит его к интерфейсуDBProfileLoader. Это позволяет изолировать логику чтения параметров конкретного процесса от ядра симулятора.Инициализация контекста: Создается отменяемый контекст выполнения:
ctx, cancel := context.WithCancel(context.Background()) ec.activeSims.Store(req.ProcessID, cancel)Offloading в бэкграунд: Тяжелый цикл вычислений запускается в отдельной горутине, а клиент мгновенно получает ответ
202 Acceptedс числом активированных цифровых двойников.
2.2 Принудительная остановка (StopHandler)
Позволяет досрочно погасить симуляцию по process_id. Из потокобезопасной карты sync.Map извлекается соответствующий context.CancelFunc, вызов которого каскадно останавливает все связанные горутины воркеров.
3. Масштабирование и Конкурентность (High-Throughput Execution)
Для обеспечения одновременной симуляции десятков тысяч цифровых двойников (агентов) в рамках одного виртуального часа, SimulationEngine реализует паттерны Fan-Out и Concurrency Throttling.
3.1 Ограничение пула через Семафор (Bounded Concurrency)
Прямой запуск горутины под каждого агента без контроля ресурсов может привести к исчерпанию дескрипторов ОС, перегрузке планировщика Go и падению RAM. Движок блокирует это за счет буферизированного канала-семафора внутри каждого временного тика:
var wg sync.WaitGroup
sem := make(chan struct{}, 5000) // Жесткий лимит на 5000 параллельных воркеров
for _, userID := range userIDs {
wg.Add(1)
go func(id int64) {
defer wg.Done()
sem <- struct{}{} // Захват слота
defer func() { <-sem }() // Освобождение слота
se.processAgentTick(ctx, id, staticProfiles[id], currentVirtualTime)
}(userID)
}
wg.Wait() // Барьер синхронизации: время не пойдет вперед, пока все не завершат тик4. Двухуровневое управление состоянием (State Hydration & Fallback)
Метод processAgentTick выполняет сборку (гидратацию) состояния агента перед передачей его в математическую модель. Движок использует гибридную схему: Локальный кэш (Redis) -> Внешняя сеть (gRPC) -> Безопасный дефолт.
flowchart TD
A[Начало тика агента] --> B{Запрос в Redis}
B -->|Найдено| C[Передача стейта в Модель]
B -->|Cache Miss / Пусто| D{Бизнес-логика реализует StateWarmer?}
D -->|Да| E[gRPC вызов Login + GetFridgeState]
E -->|Успешно| F[Сохранить в Redis] --> C
E -->|Сбой сети| G[Загрузить Default State] --> C
D -->|Нет| G
4.1 Пакетный конвейер (Redis Pipeline) и Оптимизация памяти
- Lazy Loading: Состояние прогревается только в момент реальной необходимости.
- Zero-Allocation приведение типов: Вместо использования рефлексии (
reflect), движок применяет конструкциюswitch-caseдля сырых интерфейсов из Redis, преобразуя их в примитивы без аллокаций в куче (Heap). - Пакетная запись: При инициализации больших процессов (
InitStateInRedis) используетсяrdb.Pipeline(), группирующий команды записи для минимизации сетевых задержек (RTT).
5. Схемы интеграционных данных (Примеры Payloads)
Движок не сохраняет результаты деятельности агентов в доменные базы напрямую. Взаимодействие со смежными сервисами и собственным контуром планирования происходит асинхронно через топики Apache Kafka.
После выполнения расчета поведения, движок отправляет два типа событий в Apache Kafka. Разработчикам транспортного уровня необходимо закладываться на следующие JSON-схемы:
5.1 Топик twin-history-events (Снимок состояния для аналитики)
Отправляется на каждый тик каждого агента (даже если он бездействует). Служит для сквозного логирования динамических параметров и верификации гипотез в аналитических хранилищах (например, ClickHouse).
{
"user_id": 48291,
"process_id": "proc-food-2026-v1",
"virtual_time": "2026-09-28T14:00:00+03:00",
"action": "COOKING",
"metrics": {
"current_state": "COOKING",
"current_hunger": 0.65,
"current_stress": 0.21,
"time_since_last_shop": 2,
"cached_fridge": "{\"items\":[{\"item_id\":\"a9c2-4bbf\",\"name\":\"Молоко\",\"category\":\"Молочные продукты\",\"portions\":1.5,\"weight_grams\":300,\"price\":90}]}"
}
}5.2 Топик agent-intents (Транзакционное намерение совершить действие)
Генерируется только тогда, когда действие агента отличается от IDLE. Содержит смещенное виртуальное время (Virtual Time + Delay), указывающее, когда именно в будущем действие будет совершено. Данный топик вычитывается внутренним планировщиком симулятора. Когда маркер глобального цикла currentVirtualTime догоняет время интента, Движок извлекает его и инициирует физический вызов сначала ИИ-сервиса, затем продуктового микросервиса (например, отправляет чек с продуктами в FoodTracker)
{
"user_id": 48291,
"process_id": "proc-food-2026-v1",
"action_type": "COOKING",
"virtual_time": "2026-09-28T14:45:00+03:00"
}