Files
dzentra_bot/docs/migrations/build_060_28.md

11 KiB
Raw Blame History

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

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


1. Назначение Build

Build 060.28 сделал operational checkpoint Trade Stream постоянным и добавил восстановление Runtime после перезапуска процесса.

PostgreSQL Canonical Trades остаются источником рыночных фактов. Persistent checkpoint хранит только подтверждённую точку в этой истории и позволяет восстановить bounded deduplication window до подключения к бирже.

Итоговая последовательность запуска:

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 сохраняет порядок:

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 используют единый порядок блокировок:

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:

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.