Files
dzentra_bot/docs/migrations/build_059_11.md

13 KiB
Raw Permalink Blame History

Build 059.11 — Runtime Commands

Migration Build


Цель Build

После завершения Build 059.10 Runtime уже содержит два фундаментальных уровня:

  • Runtime Protocols
  • Transport Message Models

Следующим шагом является появление объектов, описывающих намерения Runtime.

Данный Build вводит отдельный слой Runtime Commands.

Команды описывают что необходимо сделать, но не содержат логики выполнения.


Почему понадобился отдельный слой Commands

До настоящего момента Runtime умел описывать:

  • транспортные интерфейсы;
  • транспортные сообщения.

Однако отсутствовало понятие действия.

Например:

  • открыть соединение;
  • закрыть соединение;
  • зарегистрировать подписку;
  • отправить сообщение.

Все эти действия являются командами Runtime.

Они не являются:

  • транспортными сообщениями;
  • событиями Runtime;
  • сетевыми операциями.

Поэтому они выделяются в самостоятельный уровень архитектуры.


Архитектурная идея

Runtime начинает строиться по принципу Command-driven Architecture.

Получается следующая цепочка.

Runtime Service
        │
        ▼
Runtime Command
        │
        ▼
Transport
        │
        ▼
Transport Message
        │
        ▼
Network

Таким образом команды описывают исключительно намерение.

Исполнение намерения остаётся обязанностью Session и Transport.


Новый модуль

Создан файл

src/market_data/acquisition/runtime/runtime_commands.py

В нём определены immutable-модели Runtime-команд.


Использование Transport Messages

Все команды, связанные с передачей данных, используют модели Build 059.10.

То есть Runtime продолжает работать только с двумя видами транспортных сообщений:

TransportTextMessage
TransportBinaryMessage

Никакие команды не работают непосредственно со строками или массивами байтов.

Это обеспечивает единый транспортный контракт Runtime.


TransportMessage

В модуле введён локальный type alias.

TransportMessage =
    TransportTextMessage
    | TransportBinaryMessage

Он используется исключительно для типизации.

Никакой новой Runtime-модели не создаётся.

Данный alias позволяет избежать дублирования кода в командах подписки.


Новые команды

В Build добавлены шесть Runtime-команд.


ConnectCommand

Представляет намерение открыть транспортное соединение.

Команда:

  • не содержит URL;
  • не содержит параметры подключения;
  • не выполняет подключение самостоятельно.

Она лишь сообщает Runtime:

необходимо открыть соединение.


DisconnectCommand

Представляет намерение завершить соединение.

Команда не управляет транспортом.

Она только описывает действие Runtime.


Почему ConnectCommand не содержит URL

Во время проектирования рассматривались варианты добавить:

url
headers
timeout
ssl
authentication

От данной идеи было принято решение отказаться.

Причины следующие.


Причина №1

URL является частью конфигурации транспорта.

Он не должен передаваться вместе с каждой командой.


Причина №2

Команда должна описывать действие.

Не настройки транспорта.


Причина №3

Подобная архитектура позволяет легко заменить транспорт без изменения Runtime-команд.


SubscribeCommand

Представляет команду регистрации новой подписки Runtime.

Содержит два поля.

subscription_key
message

subscription_key

Строковый идентификатор подписки.

На текущем этапе Runtime он нигде не интерпретируется.

Однако именно он станет основным ключом будущего Subscription Manager.

Например:

quotes:BTCUSDT

или

candles:ETHUSDT:1m

Формат идентификатора пока намеренно не стандартизируется.

Это будет сделано позднее после проектирования Subscription Manager.


message

Содержит транспортное сообщение.

Тип поля:

TransportMessage

То есть подписка может использовать:

  • текстовое сообщение;
  • бинарное сообщение.

Runtime не анализирует содержимое payload.


Почему SubscribeCommand хранит готовое сообщение

Рассматривались два варианта.


Вариант 1

Хранить параметры подписки.

Например

symbol
interval
channel

Вариант 2

Хранить уже подготовленное транспортное сообщение.

Был выбран второй вариант.

Причины.


Runtime не знает протокол биржи

Построением JSON занимается слой выше.

Runtime не должен знать:

  • Binance;
  • Bybit;
  • Dzengi;
  • Kraken;
  • OKX.

Runtime отвечает только за доставку

Transport получает уже готовое сообщение.

Как оно было сформировано — его не касается.


UnsubscribeCommand

Представляет команду отмены существующей подписки.

Содержит:

subscription_key
message

По архитектуре полностью симметрична SubscribeCommand.

Это позволит Subscription Manager использовать единый механизм регистрации и удаления подписок.


SendTextCommand

Представляет команду отправки текстового транспортного сообщения.

Содержит

TransportTextMessage

Никаких дополнительных параметров команда не имеет.


SendBinaryCommand

Представляет команду отправки бинарного транспортного сообщения.

Содержит

TransportBinaryMessage

Runtime рассматривает его исключительно как транспортный payload.


Почему отсутствует базовый класс Command

Во время проектирования обсуждались варианты:

BaseCommand

или

RuntimeCommand

Было принято решение отказаться.

Причины.


Причина №1

Все команды являются immutable dataclass.

Общего поведения между ними нет.


Причина №2

Преждевременная иерархия усложняет архитектуру.

Добавлять её без появления реальной общей логики нецелесообразно.


Причина №3

При необходимости общий базовый тип может быть введён отдельным Build без нарушения обратной совместимости.


Почему отсутствует CommandType

Также обсуждалось использование enum.

Например.

CONNECT
DISCONNECT
SUBSCRIBE

От идеи отказались.

Тип команды уже определяется её классом.

Дополнительный enum создавал бы дублирование информации.


Почему команды ничего не делают

Очень важный архитектурный принцип Runtime.

Команды являются моделями данных.

Они:

  • ничего не выполняют;
  • не взаимодействуют с сетью;
  • не содержат asyncio;
  • не вызывают Transport;
  • не знают Session.

Это соответствует принципу Command Pattern.


Что появится позже

Исполнением команд будут заниматься Runtime Services.

Например.

Session

получает

ConnectCommand

↓

вызывает

Transport.connect()

Таким образом команда остаётся полностью независимой от реализации транспорта.


Обновлённая архитектура Runtime

После завершения Build Runtime выглядит следующим образом.

Runtime

Protocols
        │
Transport Messages
        │
Runtime Commands
        │
Transport
        │
Network

Следующим Build между Commands и Transport появятся Runtime Events.


Что НЕ входит в Build

Сознательно не реализованы:

  • Session;
  • Command Dispatcher;
  • очередь команд;
  • asyncio;
  • обработчики команд;
  • сериализация;
  • JSON;
  • Subscription Manager;
  • Reconnect;
  • Heartbeat;
  • Ping/Pong.

Все эти элементы будут появляться постепенно отдельными Build.


Проверка Build

Выполнена полная проверка.


Компиляция

python -m compileall

Успешно.


Unit Tests

Созданы тесты:

test_runtime_commands.py

Проверяется:

  • создание каждой команды;
  • корректность хранения TransportMessage;
  • поддержка текстовых сообщений;
  • поддержка бинарных сообщений;
  • immutable-поведение dataclass.

Все тесты успешно пройдены.


Runtime Regression

Проверены совместно:

  • Runtime Protocols;
  • Transport Messages;
  • Runtime Commands.

Все Runtime-тесты успешно завершены.


Проверка репозитория

Выполнен

git diff --check

Ошибок форматирования не обнаружено.


Итог

Build 059.11 завершает формирование слоя Runtime Commands.

Теперь Runtime имеет три независимых уровня:

Protocols
        │
Transport Messages
        │
Runtime Commands

Каждый уровень отвечает только за собственную область ответственности.

Это создаёт устойчивый фундамент для следующих Build, в которых будут реализованы Runtime Events, Subscription Manager, Session и механизмы обеспечения надёжности соединения.

Главный принцип миграции Dzentra остаётся неизменным:

  • архитектура развивается небольшими независимыми шагами;
  • каждый Build вводит только один новый уровень ответственности;
  • существующий торговый бот продолжает работать без необходимости полной одномоментной миграции на новую Runtime-подсистему.