11 KiB
Build 059.10 — Runtime Transport Message Models
Migration Build
Цель Build
После завершения Build 059.9 в проекте появился самостоятельный Runtime слой, содержащий транспортные контракты:
- WebSocketTransportProtocol
- WebSocketSessionProtocol
- WebSocketSubscriptionManagerProtocol
Следующим логическим шагом является создание моделей данных, которыми будут обмениваться компоненты Runtime.
Данный Build вводит первый уровень моделей Runtime — Transport Message Models.
Причина появления Transport Message Models
До настоящего момента Runtime содержал только интерфейсы взаимодействия.
Например:
Transport
│
connect()
disconnect()
send()
receive()
Однако отсутствовало описание того, какие именно объекты транспорт должен принимать и возвращать.
Использование непосредственно типов
str
bytes
делает код менее выразительным.
Невозможно определить:
- транспортное сообщение это;
- сериализованный JSON;
- бинарный protobuf;
- внутренний объект Runtime.
Поэтому вводится отдельный уровень моделей транспортных сообщений.
Архитектурная идея
Главная задача данного Build — отделить транспортные данные от всех остальных сущностей системы.
Получается следующая иерархия.
Transport
│
Transport Message
│
Parser
│
Validation
│
Mapper
│
Canonical Models
Transport знает только одно:
существует некоторый payload.
Он совершенно не знает:
- что находится внутри payload;
- как этот payload будет интерпретирован;
- является ли он JSON;
- относится ли он к конкретной бирже;
- какие модели будут построены дальше.
Это полностью соответствует принципу Single Responsibility.
Почему Runtime не знает про WebSocket
Несмотря на то, что текущим транспортом является WebSocket, Runtime проектируется максимально универсальным.
Поэтому модели транспортных сообщений намеренно не содержат слов:
- WebSocket
- Dzengi
- Exchange
- Candle
- Quote
Runtime оперирует исключительно транспортными сообщениями.
Это позволяет в будущем использовать один и тот же Runtime для различных транспортов:
- WebSocket;
- HTTP Streaming;
- FIX;
- gRPC Streaming;
- внутренние очереди сообщений.
Новые модели
Создан новый файл
src/market_data/acquisition/runtime/transport_messages.py
В Build добавлены две immutable модели.
TransportTextMessage
Представляет текстовое транспортное сообщение.
Содержит единственное поле:
payload: str
Никакой дополнительной информации модель не содержит.
Она не знает:
- что внутри находится JSON;
- является ли сообщение командой;
- является ли сообщение событием;
- содержит ли сообщение свечу.
Она является исключительно контейнером транспортного текста.
TransportBinaryMessage
Представляет бинарное транспортное сообщение.
Содержит единственное поле
payload: bytes
Как и текстовая модель, не содержит никакой информации о содержимом.
Runtime рассматривает бинарные данные как непрозрачный набор байтов.
Почему модели содержат только payload
Во время проектирования рассматривались варианты добавить дополнительные поля.
Например:
message_type
encoding
channel
metadata
timestamp
От данной идеи было принято решение отказаться.
Причины следующие.
Причина №1
Транспорт не должен ничего знать о содержимом сообщения.
Если транспорт начинает анализировать содержимое сообщения, происходит смешение ответственности между Runtime и Parser.
Причина №2
Любые дополнительные поля являются предположениями относительно будущего транспорта.
На данном этапе архитектуры неизвестно:
- понадобится ли message_type;
- понадобится ли encoding;
- понадобится ли channel;
- понадобится ли metadata.
Следовательно, преждевременно добавлять подобные поля.
Причина №3
Минимальные immutable модели проще поддерживать.
При необходимости они могут быть расширены отдельным Build без нарушения обратной совместимости.
Почему здесь отсутствуют ConnectRequest
Во время проектирования рассматривалась идея добавить модели:
ConnectRequest
DisconnectRequest
SubscribeRequest
UnsubscribeRequest
Однако было принято решение отказаться от неё.
Причина заключается в разделении уровней ответственности.
ConnectRequest не является транспортным сообщением.
Это команда Runtime.
Почему отсутствуют Ping/Pong
По аналогичной причине.
Ping и Pong являются частью логики Runtime.
Транспорт получает некоторый payload.
Что именно находится внутри этого payload, транспорт не анализирует.
Следовательно:
Ping/Pong должны появиться позднее вместе с Runtime Commands.
Новая архитектура Runtime
После завершения Build Runtime начинает разделяться на несколько независимых уровней.
Runtime
Transport Protocol
│
Transport Messages
│
Runtime Commands
│
Runtime Events
│
Runtime Services
Подобное разделение является значительно более устойчивым, чем смешение всех сущностей в одном модуле.
Обновлённый план Runtime
После выполнения Build 059.10 дальнейшее развитие Runtime выглядит следующим образом.
Build 059.11
Runtime Commands
Будут введены команды:
- ConnectCommand
- DisconnectCommand
- SubscribeCommand
- UnsubscribeCommand
- SendTextCommand
- SendBinaryCommand
Build 059.12
Runtime Events
Появятся события Runtime:
- ConnectedEvent
- DisconnectedEvent
- SubscriptionRestoredEvent
- HeartbeatTimeoutEvent
- ReconnectStartedEvent
- ReconnectCompletedEvent
Build 059.13
Subscription Manager
Полноценное управление активными подписками Runtime.
Build 059.14
WebSocket Session
Жизненный цикл Runtime Session.
Build 059.15
Transport Reliability
Инфраструктура Runtime:
- Heartbeat
- Reconnect
- Ping/Pong
- Scheduler
- Recovery
Build 059.16
Runtime Integration
Интеграция нового Runtime с существующей цепочкой Acquisition.
Build 059.17
Runtime Validation & Documentation
Полная регрессия новой архитектуры и финальная документация.
Проверка Build
Выполнены проверки.
Компиляция
python -m compileall
Успешно.
Unit Tests
test_transport_messages.py
Все тесты успешно пройдены.
Проверяется:
- создание моделей;
- корректность хранения payload;
- immutable поведение dataclass.
Runtime Regression
Проверена совместимость новой модели сообщений с ранее созданными Runtime Protocol.
Все проверки успешно завершены.
Проверка репозитория
Выполнен
git diff --check
Ошибок форматирования не обнаружено.
Итог
Build 059.10 завершает создание базового транспортного уровня Runtime.
После него Runtime уже содержит:
- транспортные контракты;
- транспортные модели сообщений.
Следующие Build будут постепенно добавлять поведение системы (Commands, Events, Session, Subscription Manager, Reconnect), не изменяя уже построенный фундамент.
Таким образом продолжается основной принцип миграции Dzentra:
- каждый Build решает одну архитектурную задачу;
- изменения являются минимальными и независимыми;
- существующая цепочка Acquisition остаётся неизменной;
- работающий торговый бот продолжает функционировать без необходимости одновременной полной миграции.