Build 060.28: implement Persistent Checkpoint and Startup Recovery
This commit is contained in:
244
docs/migrations/build_060_28.md
Normal file
244
docs/migrations/build_060_28.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# Build 060.28 — Persistent Checkpoint and Startup Recovery
|
||||
|
||||
**Engineering Migration Report**
|
||||
|
||||
---
|
||||
|
||||
## Контроль документа
|
||||
|
||||
| Свойство | Значение |
|
||||
|---|---|
|
||||
| Build | 060.28 |
|
||||
| Статус | Completed |
|
||||
| Подсистема | Market Data Acquisition / Persistent Checkpoint |
|
||||
| Компонент | Trade Stream Startup Recovery |
|
||||
| Дата завершения | 2026-08-01 |
|
||||
| Версия | 1.0 |
|
||||
|
||||
---
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `build_060_28_architecture.md` — архитектура, решения и подробные
|
||||
результаты подэтапов 060.28.0–060.28.8;
|
||||
- `build_060_27.md` — Persistent Market Data Storage;
|
||||
- `dzentra_target_architecture.md` — место Market Data Acquisition в
|
||||
целевой архитектуре Dzentra;
|
||||
- `master-roadmap.md` — дальнейшая последовательность Build.
|
||||
|
||||
---
|
||||
|
||||
## 1. Назначение Build
|
||||
|
||||
Build 060.28 сделал operational checkpoint Trade Stream постоянным и
|
||||
добавил восстановление Runtime после перезапуска процесса.
|
||||
|
||||
PostgreSQL Canonical Trades остаются источником рыночных фактов.
|
||||
Persistent checkpoint хранит только подтверждённую точку в этой истории
|
||||
и позволяет восстановить bounded deduplication window до подключения к
|
||||
бирже.
|
||||
|
||||
Итоговая последовательность запуска:
|
||||
|
||||
```text
|
||||
PostgreSQL pool + migrations
|
||||
↓
|
||||
checkpoint hydration или first-adoption
|
||||
↓
|
||||
WebSocket connect + subscription ACK
|
||||
↓
|
||||
REST Recovery при закрытом Live gate
|
||||
↓
|
||||
buffered Live в исходном порядке
|
||||
↓
|
||||
обычный Production Runtime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Завершённые подэтапы
|
||||
|
||||
| Подэтап | Название | Статус |
|
||||
|---|---|---|
|
||||
| 060.28.0 | Architecture, Contracts and Failure Policy | Accepted |
|
||||
| 060.28.1 | PostgreSQL Checkpoint Schema and Migration | Accepted |
|
||||
| 060.28.2 | Checkpoint Repository and Atomic Trade Commit | Accepted |
|
||||
| 060.28.3 | Consistency Persistence Integration | Accepted |
|
||||
| 060.28.4 | State Hydration and Deduplication Restoration | Accepted |
|
||||
| 060.28.5 | Startup Recovery and ACK/Live Boundary | Accepted |
|
||||
| 060.28.6 | Bootstrap and Lifecycle Integration | Accepted |
|
||||
| 060.28.7 | PostgreSQL Restart and Failure Verification | Accepted |
|
||||
| 060.28.8 | Final Regression and Acceptance | Accepted |
|
||||
|
||||
Каждый подэтап проходил отдельный read-only review. Findings
|
||||
исправлялись и закрывались regression-тестами до принятия.
|
||||
|
||||
---
|
||||
|
||||
## 3. Реализованная архитектура
|
||||
|
||||
### 3.1. Schema и единый repository
|
||||
|
||||
Migration 8 создала непартиционированную таблицу
|
||||
`market_data.trade_stream_checkpoints` с ключом `(venue, symbol)`.
|
||||
Checkpoint ссылается на точную Canonical Trade identity через deferred
|
||||
`ON UPDATE/DELETE NO ACTION` foreign key.
|
||||
|
||||
`PostgresTradeRepository` остаётся единственным владельцем записи
|
||||
Trades и реализует узкий `TradeCheckpointStorageProtocol`. Новая Trade и
|
||||
продвижение checkpoint выполняются одним соединением и одной
|
||||
транзакцией. Expected identity и revision обеспечивают CAS-защиту от
|
||||
stale writer; повтор уже зафиксированной candidate Trade идемпотентен.
|
||||
|
||||
Duplicate Trade обновляет provenance без продвижения persistent или
|
||||
in-memory checkpoint.
|
||||
|
||||
### 3.2. Consistency и Hydration
|
||||
|
||||
`TradeStreamConsistencyController` продвигает in-memory state только
|
||||
после успешного durable commit. Ошибка PostgreSQL является фатальной и
|
||||
не скрывается.
|
||||
|
||||
`TradeStreamStateHydrator` до запуска сети:
|
||||
|
||||
1. загружает и проверяет persistent checkpoint;
|
||||
2. восстанавливает bounded rollover-aware Trade tail;
|
||||
3. создаёт временные `TradeStreamState`;
|
||||
4. атомарно публикует весь набор в общий State Store.
|
||||
|
||||
Если после Build 060.27 история уже существует, а checkpoint ещё нет,
|
||||
последняя проверенная Trade один раз принимается как revision `1` без
|
||||
повторного наблюдения и изменения provenance.
|
||||
|
||||
### 3.3. Startup Recovery
|
||||
|
||||
`RuntimeStartupRecoveryCoordinator` выполняет blocking Hydration и REST
|
||||
Recovery через принадлежащие Runtime задачи. Cancellation ожидает уже
|
||||
начатый worker, поэтому PostgreSQL pool не закрывается под выполняющейся
|
||||
операцией.
|
||||
|
||||
Production Runtime использует одного WebSocket consumer до завершения
|
||||
startup. Он ожидает положительный subscription ACK с конечным timeout,
|
||||
складывает ранние market-сообщения в ограниченный FIFO, выполняет REST
|
||||
Recovery при закрытом общем gate и затем разбирает FIFO в исходном
|
||||
порядке.
|
||||
|
||||
Negative ACK, timeout, переполнение FIFO, повреждённый checkpoint или
|
||||
ошибка Recovery завершают startup без открытия Live processing.
|
||||
|
||||
### 3.4. Bootstrap и lifecycle
|
||||
|
||||
Отдельный checkpoint feature flag не добавлен. Persistent checkpoint
|
||||
включается только вместе с `MARKET_DATA_STORAGE_ENABLED=true` и
|
||||
использует тот же экземпляр `PostgresTradeRepository`, что и запись
|
||||
Canonical Trades.
|
||||
|
||||
Composition не выполняет I/O и не создаёт фоновых задач. Application
|
||||
сохраняет порядок:
|
||||
|
||||
```text
|
||||
pool open → migrations → Runtime start
|
||||
Runtime stop → ожидание workers → pool close
|
||||
```
|
||||
|
||||
Неполная пара Trade sink/checkpoint storage отклоняется до создания
|
||||
сетевых компонентов.
|
||||
|
||||
### 3.5. Partitions и Retention
|
||||
|
||||
Foreign key временно снимается только внутри транзакции обслуживания
|
||||
Trade partitions и восстанавливается до commit с тем же строгим
|
||||
контрактом. Попытка Retention удалить активную checkpoint Trade
|
||||
откатывает всю операцию.
|
||||
|
||||
Partition Manager и atomic writer используют единый порядок блокировок:
|
||||
|
||||
```text
|
||||
market_data.trades parent
|
||||
↓
|
||||
trades_default
|
||||
↓
|
||||
trade_stream_checkpoints
|
||||
```
|
||||
|
||||
Это исключает deadlock при одновременной записи в существующую месячную
|
||||
partition и создании новой.
|
||||
|
||||
---
|
||||
|
||||
## 4. Real PostgreSQL verification
|
||||
|
||||
Безопасный opt-in harness требует отдельную локальную базу с именем
|
||||
`dzentra_test_*` и два явных параметра:
|
||||
|
||||
- `DZENTRA_RUN_POSTGRES_TESTS=1`;
|
||||
- `DZENTRA_TEST_POSTGRES_DSN`.
|
||||
|
||||
Реальный PostgreSQL 16 подтвердил:
|
||||
|
||||
- restart с восстановлением checkpoint и deduplication tail;
|
||||
- first-adoption существующей истории 060.27;
|
||||
- отсутствие network I/O до завершения Hydration/adoption;
|
||||
- rollback ошибки до commit и восстановление после ошибки после commit;
|
||||
- фатальный orphan checkpoint и REST failure при закрытом Live gate;
|
||||
- ожидание blocking Hydration при cancellation;
|
||||
- rollover-границы `INT32_MAX → INT32_MIN` и `-1 → 0`;
|
||||
- защиту активной checkpoint Trade при Partition/Retention;
|
||||
- отсутствие deadlock между Partition Manager и atomic writer;
|
||||
- отсутствие оставшихся tasks, threads и PostgreSQL connections.
|
||||
|
||||
---
|
||||
|
||||
## 5. Финальные результаты
|
||||
|
||||
Итоговая приёмка выполнена 2026-08-01:
|
||||
|
||||
```text
|
||||
Partition lock-order unit target: 21 passed
|
||||
Restart/failure repeated ten times: 90 passed
|
||||
Partition/checkpoint race ten times: 10 passed
|
||||
Full PostgreSQL Storage integration: 51 passed
|
||||
Full integration with PostgreSQL: 64 passed
|
||||
PostgreSQL suite without opt-in: 51 skipped
|
||||
Fixed stress target: 3 passed, 1 deselected
|
||||
Full offline regression: 2305 passed, 69 deselected
|
||||
git diff --check: clean
|
||||
Untracked files whitespace check: clean
|
||||
```
|
||||
|
||||
В integration и stress наборах `ResourceWarning` считался ошибкой.
|
||||
Одноразовый PostgreSQL-контейнер после приёмки остановлен и удалён.
|
||||
Итоговый read-only review не обнаружил открытых findings.
|
||||
|
||||
---
|
||||
|
||||
## 6. Границы Build
|
||||
|
||||
Build 060.28 намеренно не реализует:
|
||||
|
||||
- общий Data Access Layer и Historical Queries;
|
||||
- Replay API и детерминированные replay-часы;
|
||||
- подключение persistent Quote/Candle consumers;
|
||||
- автоматический Retention Scheduler;
|
||||
- distributed lease, leader election и HA failover;
|
||||
- бесконечный Recovery retry/backoff.
|
||||
|
||||
Эти обязанности относятся к следующим Build. Полная итоговая ревизия
|
||||
документации Market Data Acquisition остаётся задачей Build 060.30.
|
||||
|
||||
Постороннее пользовательское изменение `.gitignore` не относится к
|
||||
Build 060.28 и не должно включаться в его staging.
|
||||
|
||||
---
|
||||
|
||||
## 7. Итог
|
||||
|
||||
Build 060.28 завершён и принят.
|
||||
|
||||
Dzentra восстанавливает подтверждённое состояние Trade Stream из
|
||||
PostgreSQL после перезапуска, заполняет downtime gap через REST и только
|
||||
после этого продолжает Live processing. Durable history, persistent
|
||||
checkpoint и in-memory state теперь продвигаются в одном проверяемом
|
||||
порядке без скрытой потери последовательности.
|
||||
|
||||
Следующий этап — Build 060.29, Market Data Access and Replay.
|
||||
Reference in New Issue
Block a user