Build 060.25: implement Production Runtime Integration

This commit is contained in:
2026-07-31 00:29:36 +03:00
parent c142145361
commit 60bec1eaf9
50 changed files with 14044 additions and 83 deletions

View File

@@ -0,0 +1,419 @@
# Build 060.25 — Production Runtime Integration
**Engineering Migration Report**
---
## Контроль документа
| Свойство | Значение |
|---|---|
| Build | 060.25 |
| Статус | Completed |
| Подсистема | Market Data Acquisition |
| Компонент | Trades Feed / Trade Stream Runtime |
| Дата завершения | 2026-07-31 |
| Версия | 1.0 |
---
## Связанные документы
- `build_060_24.md` — итог внутренней Runtime Recovery Architecture;
- `build_060_24_architecture.md` — архитектурные границы Recovery Runtime;
- `build_060_25_architecture.md` — полная спецификация Production Runtime
Integration и принятые ADR;
- `dzentra_target_architecture.md` — место Trade Stream в целевой
архитектуре Dzentra;
- `master-roadmap.md` — дальнейшая последовательность Build.
---
## 1. Назначение Build
Build 060.24 создал внутренний граф компонентов Trade Stream Runtime,
но не подключал его к реальному жизненному циклу приложения.
Цель Build 060.25 — превратить этот граф в один управляемый production
Runtime:
```text
Application Bootstrap
Production Trade Stream Factory
WebSocket connect and subscribe
Trade receive loop
├── ACK / control routing
├── Canonical Trade pipeline
├── Consistency checkpoint
└── Runtime Events
Heartbeat / Supervisor / Scheduler
reconnect → subscription restore → recovery
resume buffered live processing
```
Build сохраняет границы Transport, Acquisition, Consistency, Recovery
и Runtime. Внешний WebSocket документ становится Canonical Trade только
после прохождения существующего Acquisition pipeline.
---
## 2. Завершённые подэтапы
| Подэтап | Название | Статус |
|---|---|---|
| 060.25.0 | Static Contract Cleanup | Accepted |
| 060.25.1 | Dzengi WebSocket Transport | Accepted |
| 060.25.2 | WebSocket Session and Subscription Manager | Accepted |
| 060.25.3 | Async Runtime Event Publisher | Accepted |
| 060.25.4 | Trade Stream Production Runtime | Accepted |
| 060.25.5 | Reconnect and Recovery Integration | Accepted |
| 060.25.6 | Heartbeat and Scheduler Integration | Accepted |
| 060.25.7 | Settings, Bootstrap and Graceful Shutdown | Accepted |
| 060.25.8 | Targeted Runtime Verification | Accepted |
Каждый подэтап прошёл отдельный архитектурный review. Обнаруженные
findings исправлялись до принятия соответствующего этапа.
---
## 3. Итоговая ответственность компонентов
### DzengiWebSocketTransport
- открывает и закрывает WebSocket connection;
- отправляет и получает только `str | bytes`;
- выполняет конечный Ping/Pong liveness probe;
- не знает JSON, Trade, подписки и Recovery;
- использует отключённый встроенный WebSocket keepalive.
### WebSocketSession
- идемпотентно запускает и останавливает Transport;
- повторный `start()` не заменяет исправное OPEN-соединение;
- принудительная замена выполняется только явным reconnect.
### WebSocketSubscriptionManager
- разделяет желаемые и фактически активные подписки;
- сохраняет намерение подписаться после временной ошибки send;
- восстанавливает подписки после reconnect;
- не имитирует неподдерживаемый Dzengi unsubscribe.
### Async Runtime Event Publisher
- последовательно и с `await` доставляет событие всем Consumer;
- не создаёт скрытых background tasks;
- изолирует обычную ошибку Consumer от Runtime lifecycle;
- распространяет cancellation;
- защищён от прямой и child-task reentrancy;
- не включает чувствительный payload в аварийную диагностику.
### TradeStreamProductionRuntime
- является единственным владельцем startup, receive и Scheduler tasks;
- маршрутизирует control и market сообщения;
- передаёт Trade document в общий Acquisition/Consistency pipeline;
- связывает transport failure с reconnect и Recovery;
- выполняет полный cleanup при остановке, ошибке и cancellation.
### RuntimeReconnectRecoveryCoordinator
- обеспечивает single-flight для одного поколения соединения;
- закрывает общий live-processing gate;
- выполняет reconnect;
- восстанавливает подписки;
- запускает REST Recovery вне event loop;
- открывает live processing только после завершения Recovery;
- оставляет gate в failed state после terminal Recovery error.
### Heartbeat, Supervisor и Scheduler
- используют состояние Transport, а не частоту рыночных сделок;
- выполняют Ping/Pong с конечным timeout;
- объединяют одновременные heartbeat и receive failures в одну
reconnect/recovery operation;
- создают ровно одну Scheduler task;
- останавливаются в порядке Scheduler → Supervisor → receive loop.
### Application Runner
- владеет Telegram polling и опциональным Trade Stream Runtime;
- считает ошибку включённого Trade Stream фатальной;
- ожидает завершение обеих корневых задач;
- не позволяет повторной cancellation прервать cleanup;
- закрывает Bot session ровно один раз.
---
## 4. Production lifecycle
### Запуск
```text
load settings
feature flag disabled
└── Runtime graph не создаётся
feature flag enabled
build concrete dependency graph
start WebSocket session
send Trade subscription
start Supervisor
start receive loop and Scheduler
```
Фабрика только собирает граф зависимостей. Сетевые действия начинаются
только из `TradeStreamProductionRuntime.run()`.
### Reconnect и Recovery
```text
transport failure or failed liveness probe
capture connection generation
acquire single-flight operation
close live-processing gate
disconnect old connection
connect new connection
restore desired subscriptions
recover missing Trades through REST
process buffered live Trades
```
Recovery и live processing используют один экземпляр Consistency Layer
и не изменяют checkpoint параллельно.
### Остановка
```text
stop Scheduler
await Scheduler task
stop Supervisor
cancel and await receive loop
stop WebSocket session
clear subscriptions
close Bot session at Application boundary
```
---
## 5. Конфигурация
Trade Stream управляется отдельным безопасным feature flag:
```text
TRADE_STREAM_ENABLED
```
При включённом Runtime обязательны явные:
- WebSocket URL;
- список символов;
- transport timeouts;
- heartbeat timeout;
- Scheduler interval;
- максимальный размер Recovery Window.
Legacy WebSocket URL и `default_symbol` не используются как fallback.
Наличие `EXCHANGE_ENABLED` само по себе не включает Trade Stream.
---
## 6. Ключевые архитектурные гарантии
После Build 060.25 выполняются следующие правила:
```text
exactly one production receive loop
```
```text
exactly one scheduler task
```
```text
at most one reconnect/recovery sequence per generation
```
```text
reconnect =
disconnect
→ connect
→ restore subscriptions
```
```text
recovery precedes buffered live processing
```
```text
disabled Trade Stream creates no Runtime graph
```
```text
construction has no network side effects
```
```text
all owned tasks are cancelled or completed and awaited
```
---
## 7. Реализованные файлы
### Добавленные production-файлы
```text
app/src/bootstrap/
application.py
trade_stream_runtime.py
app/src/market_data/acquisition/adapters/dzengi/
websocket_control_message_handler.py
websocket_inbound_message_classifier.py
websocket_transport.py
app/src/market_data/acquisition/runtime/
acquisition_runtime_event_logging_consumer.py
acquisition_runtime_event_publisher.py
live_processing_gate.py
runtime_liveness_probe.py
runtime_reconnect_recovery_coordinator.py
trade_stream_production_runtime.py
websocket_inbound_message.py
websocket_session.py
websocket_subscription_manager.py
```
### Изменённые production-файлы
```text
app/.env.example
app/src/bootstrap/app_factory.py
app/src/core/config.py
app/src/integrations/exchange/rest_client.py
app/src/main.py
app/src/market_data/acquisition/exceptions.py
app/src/market_data/acquisition/runtime/reconnect.py
app/src/market_data/acquisition/runtime/scheduler.py
app/src/market_data/acquisition/runtime/supervisor.py
app/src/market_data/acquisition/trade_stream_runtime_composition.py
```
### Тесты
Добавлено или расширено покрытие:
```text
app/tests/unit/bootstrap/
app/tests/unit/core/
app/tests/unit/market_data/acquisition/adapters/dzengi/
app/tests/unit/market_data/acquisition/runtime/
app/tests/unit/market_data/acquisition/
app/tests/unit/test_main.py
```
Постороннее пользовательское изменение `.gitignore` не относится к
Build 060.25.
---
## 8. Targeted Runtime Verification
060.25.8 добавил только тестовый код и не менял production-поведение.
Через реальную production factory и реальные компоненты Runtime graph,
но с управляемыми WebSocket и REST boundaries, проверены:
1. выключенный feature flag не создаёт Runtime graph;
2. subscribe → ACK → Trade обновляет общий checkpoint;
3. ошибка connect фатальна и не оставляет задач;
4. ошибка первой subscription send полностью откатывает startup;
5. reconnect заменяет connection и восстанавливает подписку до Recovery;
6. recovered Trade обрабатывается раньше buffered live Trade;
7. Recovery error запрещает обработку buffered live Trade;
8. одновременные ошибки корневых задач наблюдаются детерминированно;
9. повторная cancellation не прерывает cleanup;
10. Bot session закрывается один раз, owned tasks всегда await-ятся.
Итоговый read-only review 060.25.8 новых findings не выявил.
---
## 9. Результаты тестирования
Повторная проверка выполнена 2026-07-31:
```text
Expanded Production Runtime target: 445 passed
Full project regression: 1869 passed
```
Тесты не используют реальную сеть, production credentials или
недетерминированные внешние задержки.
---
## 10. Что не входит в Build
Build 060.25 не реализует:
- длительные live exchange и network fault scenarios;
- production stress certification;
- persistent market data storage;
- persistent checkpoint;
- startup recovery после перезапуска процесса;
- historical query и Replay API;
- аналитические вычисления поверх исторических данных.
Эти задачи относятся к следующим Build и зафиксированы в
`master-roadmap.md`.
---
## 11. Итог
Build 060.25 завершён.
Trade Stream подключён к bootstrap приложения как отдельный,
отключённый по умолчанию production Runtime. Он управляет реальным
WebSocket lifecycle, восстанавливает подписки и пропущенные сделки,
сохраняет порядок Recovery и Live processing и детерминированно
освобождает принадлежащие ему ресурсы.
Следующий этап — Build 060.26, посвящённый интеграционным, fault,
reconnect, recovery и stress-сценариям за пределами детерминированного
in-process unit harness.

File diff suppressed because it is too large Load Diff