227 lines
10 KiB
Markdown
227 lines
10 KiB
Markdown
# Build 060.27 — Persistent Market Data Storage
|
||
|
||
**Engineering Migration Report**
|
||
|
||
---
|
||
|
||
## Контроль документа
|
||
|
||
| Свойство | Значение |
|
||
|---|---|
|
||
| Build | 060.27 |
|
||
| Статус | Completed |
|
||
| Подсистема | Market Data Acquisition / Persistent Storage |
|
||
| Компонент | Canonical Market Data Storage |
|
||
| Дата завершения | 2026-08-01 |
|
||
| Версия | 1.0 |
|
||
|
||
---
|
||
|
||
## Связанные документы
|
||
|
||
- [Build 060.27 Architecture](build_060_27_architecture.md) — архитектура,
|
||
решения и подробные результаты подэтапов 060.27.0–060.27.8;
|
||
- [Build 060.26 Engineering Migration Report](build_060_26.md) — итог
|
||
Runtime Integration and Regression;
|
||
- [Dzentra Target Architecture](../architecture/dzentra_target_architecture.md) —
|
||
место Market Data Storage в целевой архитектуре Dzentra;
|
||
- [Master Roadmap](../roadmap/master-roadmap.md) — дальнейшая
|
||
последовательность Build.
|
||
|
||
---
|
||
|
||
## 1. Назначение Build
|
||
|
||
Build 060.27 добавил долговременное PostgreSQL-хранилище Canonical
|
||
Market Data. Production Trade Stream теперь может сохранять Trades
|
||
независимо от времени жизни процесса, а Quotes и Candles получили
|
||
готовые storage-контракты и repositories без подключения существующих
|
||
consumers.
|
||
|
||
Главная гарантия интеграции:
|
||
|
||
```text
|
||
validated Canonical Trade
|
||
↓
|
||
durable PostgreSQL write
|
||
↓
|
||
operational checkpoint advancement
|
||
```
|
||
|
||
Ошибка включённого persistent storage является фатальной. Runtime не
|
||
продвигает checkpoint и не продолжает работу так, будто Trade сохранён.
|
||
|
||
---
|
||
|
||
## 2. Завершённые подэтапы
|
||
|
||
| Подэтап | Название | Статус |
|
||
|---|---|---|
|
||
| 060.27.0 | Storage Contract and Boundaries | Accepted |
|
||
| 060.27.1 | PostgreSQL Schema, Migrations and Pool | Accepted |
|
||
| 060.27.2 | Persistent Trade Repository | Accepted |
|
||
| 060.27.3 | Quote and Candle Repositories | Accepted |
|
||
| 060.27.4 | Storage API and Retention | Accepted |
|
||
| 060.27.5 | Trade Runtime Persistence Integration | Accepted |
|
||
| 060.27.6 | Bootstrap and Lifecycle Integration | Accepted |
|
||
| 060.27.7 | Integration and Failure Verification | Accepted |
|
||
| 060.27.8 | Final Regression and Acceptance | Accepted |
|
||
|
||
Каждый подэтап проходил отдельный read-only review. Findings
|
||
исправлялись и закрывались regression-тестами до принятия.
|
||
|
||
---
|
||
|
||
## 3. Реализованная архитектура
|
||
|
||
### 3.1. Schema, migrations и pool
|
||
|
||
Создана PostgreSQL schema `market_data` с partitioned таблицами:
|
||
|
||
- `trades` — Canonical Trades;
|
||
- `quotes` — неизменяемые Canonical Quote snapshots;
|
||
- `candle_revisions` — наблюдавшиеся ревизии Candles;
|
||
- `partition_registry` — реестр Dzentra-managed partitions.
|
||
|
||
Семь упорядоченных миграций применяются в одной транзакции под
|
||
transaction-level advisory lock. История хранится в
|
||
`public.storage_schema_migrations`; неизвестная версия или другое имя
|
||
миграции являются фатальным schema mismatch.
|
||
|
||
`PostgresConnectionPool` не выполняет I/O в конструкторе. Pool явно
|
||
открывается Application lifecycle перед Runtime и закрывается только
|
||
после полной остановки Trade Runtime.
|
||
|
||
### 3.2. Canonical repositories
|
||
|
||
Repository-контракты различают три результата:
|
||
|
||
- `INSERTED` — сохранено новое событие;
|
||
- `DUPLICATE` — идентичное событие уже существует;
|
||
- `PROVENANCE_UPDATED` — Canonical payload совпал, добавлен новый путь
|
||
наблюдения.
|
||
|
||
Trade identity задаётся `venue + symbol + trade_id + executed_at`.
|
||
Время защищает историю от коллизии после полного signed 32-bit rollover
|
||
Trade ID. Разный transport source не создаёт Canonical conflict, а
|
||
различие цены, количества, времени или стороны создаёт явную ошибку.
|
||
|
||
Quote identity использует `venue + symbol + received_at`. Candle
|
||
identity использует `venue + symbol + interval + open_time +
|
||
observed_at`, поэтому промежуточные и финальные ревизии не
|
||
перезаписываются скрытно.
|
||
|
||
Одиночные и пакетные операции транзакционны. Конфликт или database
|
||
error откатывает всю пакетную запись.
|
||
|
||
### 3.3. Partitions и retention
|
||
|
||
Каждая основная таблица имеет default partition. Управляемый partition
|
||
manager под общим advisory lock:
|
||
|
||
1. проверяет фактическое состояние PostgreSQL и registry;
|
||
2. создаёт месячную таблицу;
|
||
3. переносит подходящие default rows;
|
||
4. подключает partition в той же транзакции.
|
||
|
||
Retention по умолчанию выключен. Явный запуск удаляет только
|
||
зарегистрированные истёкшие partitions и строки раньше точного UTC
|
||
cutoff. Очистка всех выбранных типов выполняется атомарно.
|
||
|
||
### 3.4. Runtime и Bootstrap
|
||
|
||
Live и Recovery используют один `TradeObservationSinkProtocol` через
|
||
общий `TradeStreamConsistencyController`. Единственный владелец записи
|
||
обеспечивает одинаковую последовательность для обоих путей данных.
|
||
|
||
Синхронная PostgreSQL-запись выполняется вне asyncio event loop через
|
||
принадлежащую Runtime задачу. Cancellation ожидает уже начатую запись и
|
||
не оставляет фонового worker.
|
||
|
||
Storage включается только явным `MARKET_DATA_STORAGE_ENABLED=true` и
|
||
требует включённый Trade Stream. При выключенном флаге зависимости не
|
||
строятся, pool не открывается, migrations не запускаются.
|
||
|
||
---
|
||
|
||
## 4. Real PostgreSQL verification
|
||
|
||
Безопасный opt-in harness требует одновременно:
|
||
|
||
- `DZENTRA_RUN_POSTGRES_TESTS=1`;
|
||
- отдельный `DZENTRA_TEST_POSTGRES_DSN`;
|
||
- явный localhost, loopback address или local socket;
|
||
- имя базы с префиксом `dzentra_test_`.
|
||
|
||
PostgreSQL service, неявный endpoint и смешанный local/remote fallback
|
||
запрещены. Перед destructive cleanup harness повторно проверяет точное
|
||
имя фактической базы и специальное имя контрольного соединения.
|
||
|
||
Настоящий PostgreSQL подтвердил:
|
||
|
||
- атомарность migrations и repositories;
|
||
- участие обеих concurrent migration/partition caller-сессий;
|
||
- insert, duplicate, provenance и conflict paths;
|
||
- перенос default rows и точность retention cutoff;
|
||
- Runtime persistence через Live и reconnect/recovery;
|
||
- fatal propagation database failure;
|
||
- правильное закрытие pool и отсутствие оставшихся соединений.
|
||
|
||
---
|
||
|
||
## 5. Финальные результаты
|
||
|
||
Итоговая приёмка выполнена 2026-08-01:
|
||
|
||
```text
|
||
Targeted Storage/Runtime unit suite: 307 passed
|
||
PostgreSQL control run: 15 passed
|
||
PostgreSQL repeated ten times: 150 passed
|
||
Combined integration suite: 26 passed
|
||
Fixed stress target: 3 passed, 1 deselected
|
||
PostgreSQL suite without opt-in: 15 skipped
|
||
Full offline regression: 2119 passed, 31 deselected
|
||
git diff --check: clean
|
||
Untracked files diff check: clean
|
||
```
|
||
|
||
В integration и stress наборах `ResourceWarning` считался ошибкой.
|
||
Одноразовый PostgreSQL 16 работал на `tmpfs` и после приёмки был
|
||
остановлен и удалён. Итоговый read-only review не обнаружил открытых
|
||
findings.
|
||
|
||
---
|
||
|
||
## 6. Границы Build
|
||
|
||
Build 060.27 намеренно не реализует:
|
||
|
||
- persistent Runtime checkpoint;
|
||
- Startup Recovery после перезапуска процесса;
|
||
- Historical Queries и Data Access Layer;
|
||
- Replay API и Analytics API;
|
||
- автоматический partition/retention scheduler;
|
||
- подключение существующих Quote/Candle consumers;
|
||
- хранение raw exchange documents.
|
||
|
||
Persistent Checkpoint и Startup Recovery относятся к Build 060.28.
|
||
Historical Access и Replay относятся к Build 060.29. Полная итоговая
|
||
ревизия документации подсистемы остаётся задачей Build 060.30.
|
||
|
||
Постороннее пользовательское изменение `.gitignore` не относится к
|
||
Build 060.27 и не должно включаться в его staging.
|
||
|
||
---
|
||
|
||
## 7. Итог
|
||
|
||
Build 060.27 завершён и принят.
|
||
|
||
Dzentra получила транзакционное долговременное хранилище Canonical
|
||
Market Data и production persistence для Trades. Operational checkpoint
|
||
теперь продвигается только после подтверждённой durable-записи, а
|
||
ошибка Storage завершает Runtime без скрытой потери истории.
|
||
|
||
Следующий этап — [Build 060.28](build_060_28.md), Persistent Checkpoint
|
||
and Startup Recovery.
|