Метод 17: flush_session_state()

Домен: SIMULATION | Контур: Фиксация измененных привычек и биологических часов

WarningОграничение публичной документации

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

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

1. Бизнес-спецификация метода

  • Идентификатор метода: BPDS-SIM-M017
  • Системное имя: flush_session_state(twin_id: UUID, current_tick: Long, scenario: ScenarioEnum)
  • Микросервис: simulation-core-engine
  • Домен: SIMULATION
  • Класс / Компонент: simulation.engine.core.CoreSimulationEngineImpl

1.1. Описание логики работы

Этот метод является финальной точкой всего часового цикла (такта) симуляции. Он запускается только тогда, когда Метод 16 подтвердил, что реальное приложение и его база данных успешно обновили продукты в холодильнике.

Задача метода — зафиксировать полученный пользователем опыт в его долговременную память. Симулятор имитирует психологию человека: 1. Насыщение: Если пользователь только что поел, симулятор обнуляет его внутренний показатель голода в оперативной памяти (RAM) и записывает номер текущего часа симуляции как время последнего приема пищи. Одновременно в базе увеличивается его интерес к готовой еде (подкрепление лени). 2. Изменение привычек: Если пользователь совершил закупку продуктов, его интерес к этой категории падает (он затарился, у него пропал стимул покупать это снова).

Метод атомарно обновляет быструю оперативную память, а затем сбрасывает новые личные веса и время еды в базу данных симулятора через команду UPSERT (вставка или обновление при конфликте). После этого сессия текущего часа закрывается, а виртуальный поток уничтожается.

1.2. Пошаговое выполнение

  1. Расчет изменений характера: На основе завершенного сценария аналитическое ядро рассчитывает новые значения личных весов предпочтений \(K\). При покупке или готовке коэффициент категории падает на 15%, при поедании готовой еды — голод сбрасывается в стартовые 0.1000, а вес готовой еды растет на 15%.
  2. Атомарный сдвиг RAM: Новые показатели весов и сброшенный голод записываются в оперативную память (ConcurrentHashMap), заменяя старый кэш.
  3. Фиксация биологических часов: Формируется SQL-запрос к таблице снапшотов. Симулятор записывает текущий номер часа current_tick в поле последней еды.
  4. Фиксация весов в СУБД: Формируется SQL-запрос к таблице личных весов. Новые привычки пользователя «запекаются» в постоянную базу данных симулятора.
  5. Закрытие такт-сессии: Виртуальный поток воркера удаляет сквозной X-Request-ID из памяти логирования и успешно завершает работу до следующего вызова.

2. Диаграмма последовательности метода (Вход и Выход флоу)

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

sequenceDiagram
    autonumber
    participant Core as CoreSimulationEngineImpl
    participant Map as Оперативная память (RAM кэш)
    participant DB as База Данных Симулятора

    %% ВХОД МЕТОДА
    Core->>Core: Вызов flushSessionState(twin_id, tick, scenario)
    Note over Core: Вход метода: twin_id, текущий такт и тип завершенного действия
    
    %% ОБНОВЛЕНИЕ ОПЕРАТИВНОЙ ПАМЯТИ
    Core->>Core: Расчет новых личных весов K и сброса голода
    Core->>Map: Атомарное обновление cache.replace(twin_id, newContext)
    activate Map
    Map-->>Core: Подтверждено (RAM обновлена)
    deactivate Map

    %% ФИЗИЧЕСКИЙ СБРОС В ПОСТГРЕС СИМУЛЯТОРА
    Note over Core: Запуск транзакции фиксации опыта в СУБД симулятора
    
    par Фиксация биологического времени еды
        Core->>DB: SQL UPSERT INTO twin_state_snapshots (last_tick_updated = tick)
        activate DB
        DB-->>Core: База данных: Снапшот сохранен
        deactivate DB
    and Фиксация долговременных привычек
        Core->>DB: SQL UPSERT INTO twin_weight_preferences (weight = K_new)
        activate DB
        DB-->>Core: База данных: Веса K сохранены
        deactivate DB
    end
    
    Core->>Core: MDC.remove("X-Request-ID")
    Note over Core: Выход метода: Успешное закрытие транзакции такта. Виртуальный поток уничтожен.


3. Схемы данных и SQL-взаимодействие

Этот метод выполняет два критически важных UPSERT запроса к внутренней PostgreSQL симулятора для фиксации состояния.

3.1. Сброс биологических часов голода (Запрос к twin_state_snapshots)

Запрос перезаписывает номер текущего часа симуляции (105), обнуляя скаляр голода до сытого состояния:

INSERT INTO simulation.twin_state_snapshots (twin_id, hunger_x0, last_tick_updated, updated_at)
VALUES ('d3b07384-d113-4956-bf8a-e421cd7bf777'::uuid, 0.1000, 105, CURRENT_TIMESTAMP)
ON CONFLICT (twin_id) 
DO UPDATE SET 
    hunger_x0 = EXCLUDED.hunger_x0,
    last_tick_updated = EXCLUDED.last_tick_updated,
    updated_at = EXCLUDED.updated_at;

3.2. Мутация долговременных привычек (Запрос к twin_weight_preferences)

Запрос фиксирует изменение характера покупок твина: из-за того, что он купил фрукты, его интерес к ним падает до 1.0813, снижая частоту закупа на следующих тактах:

INSERT INTO simulation.twin_weight_preferences (twin_id, category_id, preference_weight_k, updated_at)
VALUES ('d3b07384-d113-4956-bf8a-e421cd7bf777'::uuid, 'FRUITS', 1.0813, CURRENT_TIMESTAMP)
ON CONFLICT (twin_id, category_id) 
DO UPDATE SET 
    preference_weight_k = EXCLUDED.preference_weight_k,
    updated_at = EXCLUDED.updated_at;

4. Спецификация обмена данными (Вход / Выход)

Данные сохраняются во внутренние структуры репозиториев микросервиса.

4.1. Входные параметры фиксации опыта (Входные параметры для метода)

{
  "twin_id": "d3b07384-d113-4956-bf8a-e421cd7bf777",
  "current_simulation_tick": 105,
  "successful_scenario": "SCENARIO_CONSUMING_FOOD"
}

4.2. Результат закрытия такт-сессии (Выходные параметры)

{
  "committed_twin_id": "d3b07384-d113-4956-bf8a-e421cd7bf777",
  "ram_cache_status": "SYNCHRONIZED_WITH_DATABASE",
  "database_upsert_status": "ACID_COMMIT_SUCCESS"
}

5. ЗАДАЧА ДЛЯ РАЗРАБОТЧИКА: BACKEND

Заголовок: Реализация финального метода фиксации состояния и мутации привычек flush_session_state

5.1. Что нужно сделать

  1. Написать приватный метод flushSessionState внутри центрального сервиса оркестрации CoreSimulationEngineImpl.
  2. Реализовать логику пересчета весов: если передан сценарий CONSUME, вызывать метод context.preferenceVectorK().put("READY_MEALS", oldWeight * 1.15). Если сценарий BUY, снижать вес купленной категории на 15%.
  3. Выполнить обновление оперативной памяти симулятора через метод cache.replace(twinId, updatedContext).
  4. Внедрить вызовы репозиториев SimulationSnapshotRepository и TwinWeightPreferencesRepository для трансляции данных в PostgreSQL.
  5. Обеспечить выполнение обоих SQL-запросов INSERT ... ON CONFLICT DO UPDATE внутри единой физической транзакции Spring @Transactional(propagation = Propagation.REQUIRED). Если один из запросов падает, вся мутация привычек твина должна быть полностью откачена (Rollback) во избежание рассинхронизации RAM и БД.

6. ЗАДАЧА ДЛЯ РАЗРАБОТЧИКА: МИГРАЦИЯ

Заголовок: Настройка параметров автовакуума (Autovacuum) для таблиц весов и снапшотов в СУБД симулятора

6.1. Что нужно сделать

Поскольку 1500 виртуальных потоков пользователей симулятора на каждом такте будут непрерывно выполнять тяжелые UPDATE/UPSERT запросы к таблицам twin_state_snapshots и twin_weight_preferences, в PostgreSQL симулятора будет скапливаться колоссальное количество «мертвых» строк (Dead Rows/Tuples). Без агрессивной очистки база данных симулятора раздуется и начнет тормозить уже через несколько сотен тактов. Задача миграции — наложить агрессивный профиль очистки автовакуума СУБД на эти две таблицы.

-- Изменения для базы данных симулятора (схема simulation)
-- Запуск очистки таблицы снапшотов при мутации каждых 5% строк
ALTER TABLE simulation.twin_state_snapshots SET (autovacuum_vacuum_scale_factor = 0.05);
ALTER TABLE simulation.twin_state_snapshots SET (autovacuum_analyze_scale_factor = 0.02);

-- Запуск очистки таблицы весов при мутации каждых 5% строк
ALTER TABLE simulation.twin_weight_preferences SET (autovacuum_vacuum_scale_factor = 0.05);
ALTER TABLE simulation.twin_weight_preferences SET (autovacuum_analyze_scale_factor = 0.02);