Files
dzentra_bot/docs/migrations/build_060_24.md

19 KiB
Raw Permalink Blame History

Build 060.24 — Runtime Recovery Architecture

Engineering Migration Report


Контроль документа

Свойство Значение
Build 060.24
Название Runtime Recovery Architecture
Статус Completed
Проект Dzentra
Подсистема Market Data Acquisition
Компонент Trade Stream Runtime
Версия документа 2.0

Связанные документы


1. Исходное состояние

После Build 060.23 проект имел рабочий конвейер обработки одной live-сделки:

WebSocket message
        │
        ▼
TradeStreamMessageAdapterProtocol
        │
        ▼
Canonical Trade
        │
        ▼
TradeStreamConsistencyController
        │
        ▼
Trade | None

Также уже существовал REST Recovery Layer:

TradeRecoveryRequest
        │
        ▼
TradeRecoveryController
        │
        ▼
TradeRecoveryNormalizer
        │
        ▼
TradeStreamConsistencyController

Эти два конвейера использовали Consistency Layer, но Runtime ещё не обладал архитектурой обнаружения потери активности, повторного подключения и координации восстановления пропущенного диапазона.

2. Цель Build

Цель Build 060.24 — реализовать внутреннюю Runtime Recovery Architecture:

  • определить единственный checkpoint Trade Stream;
  • представить и рассчитать допустимые окна восстановления;
  • реализовать изолированные runtime-компоненты reconnect, heartbeat, supervisor и scheduler;
  • связать checkpoint, planner и существующий Recovery Controller;
  • построить единый граф зависимостей Live Stream и Recovery;
  • не запускать production lifecycle и не создавать сетевые подключения во время композиции.

Build создаёт завершённую архитектурную основу восстановления в памяти. Её подключение к реальному WebSocket lifecycle, bootstrap приложения и production-конфигурации относится к Build 060.25.


3. Выполненный roadmap

Подэтап Название Фактическая реализация
060.24.1 RuntimeCheckpoint TradeStreamState.last_trade
060.24.2 RuntimeSessionState RuntimeSupervisorState и локальные состояния runtime-компонентов
060.24.3 RecoveryPlanner TradeRecoveryWindowPlanner
060.24.4 RecoveryWindowCalculator алгоритм TradeRecoveryWindowPlanner.build_windows()
060.24.5 ReconnectCoordinator ReconnectCoordinator
060.24.6 Heartbeat HeartbeatMonitor
060.24.7 Supervisor RuntimeSupervisor
060.24.8 Scheduler RuntimeScheduler
060.24.9.1 RuntimeRecoveryCoordinator RuntimeRecoveryProtocol и RuntimeRecoveryCoordinator
060.24.9.2 Runtime Composition TradeStreamRuntimeComposition и factory-функция сборки

RuntimeSessionState не введён как отдельная дублирующая модель. Состояние runtime-сессии выражено через RuntimeSupervisorState, а локальные детали принадлежат ReconnectState и HeartbeatState.

RecoveryWindowCalculator не введён как отдельный класс. Расчёт является единственной ответственностью TradeRecoveryWindowPlanner, поэтому его выделение создало бы искусственный слой без самостоятельного состояния или политики.


4. Реализованные компоненты

4.1. RuntimeCheckpoint

TradeStreamState хранит:

last_trade_id
last_trade
recent trade window

Checkpoint — это last_trade, то есть последняя каноническая сделка, принятая Consistency Layer.

Он обновляется только после успешного accept(). Полный дубликат, конфликтующий дубликат, нарушение порядка или неожиданный symbol не переводят checkpoint вперёд.

Основной инвариант:

last_trade is None
⇔
last_trade_id is None

Если checkpoint существует:

last_trade.trade_id == last_trade_id
last_trade.symbol == TradeStreamState.symbol

Checkpoint находится только в оперативной памяти. Его долговременное хранение относится к Build 060.28.

4.2. TradeRecoveryWindow

TradeRecoveryWindow — immutable value object с slots:

symbol
start_time
end_time

Модель проверяет типы и запрещает:

  • пустой symbol;
  • отрицательные временные границы;
  • start_time > end_time;
  • использование bool вместо целочисленного timestamp.

Window не выполняет Recovery и не содержит transport-, retry- или exchange-состояние.

4.3. TradeRecoveryWindowPlanner

Planner принимает полный диапазон и возвращает:

tuple[TradeRecoveryWindow, ...]

Каждое окно удовлетворяет ограничению существующего TradeRecoveryRequest:

end_time - start_time < 3_600_000 ms

Значение по умолчанию:

3_599_999 ms

Соседние окна имеют общую границу:

previous.end_time == next.start_time

Возможный повтор сделки на границе устраняется общим Consistency Layer. При равных start_time и end_time Planner возвращает пустой tuple.

Planner:

  • не выполняет REST-запросы;
  • не создаёт TradeRecoveryRequest;
  • не читает системное время;
  • не зависит от WebSocket и Runtime lifecycle.

4.4. ReconnectCoordinator

ReconnectCoordinator выполняет одну попытку reconnect:

ReconnectStartedEvent
        │
        ▼
ConnectCommand
        │
        ▼
restore_subscriptions()
        │
        ▼
ReconnectCompletedEvent

При ошибке публикуется ReconnectFailedEvent, состояние переходит в FAILED, а исходное исключение распространяется вызывающему коду.

Coordinator хранит номер попытки и состояние:

DISCONNECTED
CONNECTING
RESTORING_SUBSCRIPTIONS
CONNECTED
FAILED

Retry loop и backoff в этот компонент не входят.

4.5. HeartbeatMonitor

Heartbeat является пассивным монитором:

  • использует monotonic clock;
  • хранит время последней активности;
  • определяет timeout детерминированным вызовом check_timeout();
  • публикует один HeartbeatTimeoutEvent на один период отсутствия активности;
  • возвращается в monitoring после новой активности.

Heartbeat не создаёт фоновых задач, не выполняет reconnect и не управляет WebSocket.

4.6. RuntimeSupervisor

Supervisor владеет состоянием runtime-сессии:

STOPPED
RUNNING
RECONNECTING
FAILED

Он:

  • запускает и останавливает Heartbeat;
  • принимает уведомления об активности;
  • запускает одну reconnect-попытку после подтверждённого timeout;
  • предотвращает параллельный reconnect;
  • после успешного reconnect начинает новый heartbeat-период;
  • сохраняет FAILED и распространяет ошибку reconnect.

Supervisor не выполняет периодический цикл, recovery, retry или backoff.

4.7. RuntimeScheduler

Scheduler отвечает только за периодичность:

HeartbeatMonitor.check_timeout()
        │
        ├── False → следующий интервал
        │
        └── True  → RuntimeSupervisor.handle_heartbeat_timeout()

Цикл запускается явным await RuntimeScheduler.start(). Scheduler не создаёт asyncio.Task самостоятельно. stop() запрашивает безопасное завершение на ближайшей управляемой границе.

4.8. RuntimeRecoveryCoordinator

Coordinator соединяет существующие слои:

TradeStreamStateStore
        │
        ▼
TradeStreamState.last_trade
        │
        ▼
executed_at → Unix milliseconds
        │
        ▼
TradeRecoveryWindowPlanner
        │
        ▼
TradeRecoveryRequest[]
        │
        ▼
TradeRecoveryController
        │
        ▼
aggregated TradeRecoveryResult

Свойства реализации:

  • использует существующее состояние и не создаёт новый TradeStreamState;
  • принимает recovery_end_time от вызывающего runtime-компонента;
  • преобразует только timezone-aware datetime;
  • не использует float при переводе времени в Unix milliseconds;
  • выполняет окна последовательно;
  • объединяет восстановленные сделки в один результат;
  • не скрывает ошибки Store, Planner или Recovery Controller.

При отсутствии состояния или checkpoint возвращается пустой TradeRecoveryResult; обе его границы равны recovery_end_time.

4.9. Runtime Composition

Factory:

build_trade_stream_runtime_composition(...)

создаёт один граф зависимостей и возвращает immutable TradeStreamRuntimeComposition.

Ключевой identity-инвариант:

Live Stream ───┐
               ├── one TradeStreamConsistencyController
Recovery ──────┘
                         │
                         ▼
               one TradeStreamStateStore

Благодаря этому live-сделки и восстановленные сделки проходят одинаковые правила согласованности и используют один checkpoint.

Внешние WebSocket-зависимости передаются через Protocol-контракты. Создание Composition:

  • не читает Settings;
  • не создаёт production transport;
  • не подключается к сети;
  • не запускает Scheduler или Supervisor;
  • не создаёт фоновые задачи;
  • не выполняет Recovery.

5. Архитектурные границы

После Build действуют следующие границы.

Компонент Владеет Не владеет
TradeStreamState checkpoint и deduplication window recovery orchestration
TradeRecoveryWindowPlanner расчёт окон REST и runtime lifecycle
ReconnectCoordinator одна reconnect-попытка retry, backoff и recovery
HeartbeatMonitor контроль активности scheduling и reconnect
RuntimeSupervisor состояние сессии и реакция на timeout периодический цикл и recovery
RuntimeScheduler периодический вызов проверок reconnect-логика и heartbeat-вычисления
RuntimeRecoveryCoordinator recovery orchestration одного symbol WebSocket lifecycle
Composition root создание и связывание объектов запуск production lifecycle

Ни один из компонентов Build не импортирует bootstrap приложения, торговую логику или Telegram-инфраструктуру.


6. Состав изменений

Production

app/src/market_data/acquisition/
├── consistency/
│   └── trade_stream_state.py
├── recovery/
│   ├── trade_recovery_window.py
│   └── trade_recovery_window_planner.py
├── runtime/
│   ├── heartbeat.py
│   ├── reconnect.py
│   ├── runtime_recovery_coordinator.py
│   ├── runtime_recovery_protocol.py
│   ├── scheduler.py
│   └── supervisor.py
└── trade_stream_runtime_composition.py

Tests

app/tests/unit/market_data/acquisition/
├── consistency/
│   └── test_trade_stream_state.py
├── recovery/
│   ├── test_trade_recovery_window.py
│   └── test_trade_recovery_window_planner.py
├── runtime/
│   ├── test_heartbeat_monitor.py
│   ├── test_reconnect_coordinator.py
│   ├── test_runtime_recovery_coordinator.py
│   ├── test_runtime_scheduler.py
│   └── test_runtime_supervisor.py
└── test_trade_stream_runtime_composition.py

Documentation

docs/migrations/
├── build_060_24.md
└── build_060_24_architecture.md

Изменение .gitignore, присутствующее в рабочем дереве, не является частью Build 060.24.


7. Тестирование

Непосредственно связанные с Build девять тестовых модулей содержат 230 тестов.

Область Тестов
Trade Stream State 24
Recovery Window 20
Recovery Window Planner 36
Reconnect Coordinator 15
Heartbeat Monitor 28
Runtime Supervisor 25
Runtime Scheduler 30
Runtime Recovery Coordinator 27
Runtime Composition 25
Итого 230

Контрольный результат:

230 passed

Полная регрессия проекта:

1620 passed
0 failed

Тесты являются unit- и composition-тестами. Реальные сценарии WebSocket disconnect, повторной подписки, reconnect → recovery и стресс-тестирование относятся к Build 060.25060.26.


8. Обратная совместимость

Build сохраняет существующие публичные контракты:

  • каноническая модель Trade не изменена;
  • Recovery Controller и Recovery Request не изменены;
  • live acquisition продолжает использовать Consistency Protocol;
  • transport protocols остаются внешними зависимостями Runtime;
  • main.py и bootstrap не изменены.

Расширение TradeStreamState добавляет checkpoint, не изменяя контракт accept().


9. Что не входит в Build

Build 060.24 не включает:

  • создание production WebSocket transport/session;
  • подключение Composition к main.py или bootstrap;
  • запуск scheduler-задачи;
  • передачу live-активности в Supervisor;
  • выбор symbol и recovery_end_time для production recovery;
  • автоматическую цепочку reconnect → recovery;
  • переключение между Recovery и Live Stream;
  • retry/backoff policy;
  • постоянное хранение checkpoint;
  • интеграционные reconnect/recovery и stress tests.

Эти ограничения означают, что формулировка «Trade Stream самостоятельно переживает обрыв WebSocket» на данном этапе является архитектурной целью, а не активированным production-поведением.

Production Runtime Integration выполняется в Build 060.25.


10. Definition of Done

  • Checkpoint принадлежит TradeStreamState.
  • Checkpoint обновляется только принятой сделкой.
  • Реализована immutable-модель Recovery Window.
  • Реализован расчёт одного или нескольких допустимых окон.
  • Реализована одна reconnect-попытка и восстановление подписок.
  • Реализован пассивный Heartbeat.
  • Реализовано состояние и поведение Runtime Supervisor.
  • Реализован периодический Runtime Scheduler.
  • Реализован Runtime Recovery Coordinator.
  • Реализована Runtime Composition с общим Consistency Layer.
  • Создание Composition не имеет lifecycle- и network-side effects.
  • Целевые тесты проходят.
  • Полная регрессия проходит.
  • Production lifecycle подключён к приложению — Build 060.25.
  • End-to-end reconnect/recovery проверен — Build 060.25060.26.

11. Итог

Build 060.24 завершает внутреннюю Runtime Recovery Architecture.

Проект располагает:

  • надёжным checkpoint в Consistency Layer;
  • детерминированным планированием Recovery Window;
  • изолированными компонентами reconnect, heartbeat, supervisor и scheduler;
  • координатором последовательного восстановления;
  • явным composition root с единым состоянием для live и recovery.

Следующий этап не должен заново проектировать эти компоненты. Задача Build 060.25 — подключить готовый граф к production WebSocket lifecycle и определить end-to-end порядок запуска, reconnect и recovery.