build 059.11: add runtime command models
This commit is contained in:
580
docs/migrations/build_059_11.md
Normal file
580
docs/migrations/build_059_11.md
Normal file
@@ -0,0 +1,580 @@
|
||||
# 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.
|
||||
|
||||
Получается следующая цепочка.
|
||||
|
||||
```text
|
||||
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.
|
||||
|
||||
```python
|
||||
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.
|
||||
|
||||
Например.
|
||||
|
||||
```text
|
||||
Session
|
||||
|
||||
получает
|
||||
|
||||
ConnectCommand
|
||||
|
||||
↓
|
||||
|
||||
вызывает
|
||||
|
||||
Transport.connect()
|
||||
```
|
||||
|
||||
Таким образом команда остаётся полностью независимой от реализации транспорта.
|
||||
|
||||
---
|
||||
|
||||
# Обновлённая архитектура Runtime
|
||||
|
||||
После завершения Build Runtime выглядит следующим образом.
|
||||
|
||||
```text
|
||||
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 имеет три независимых уровня:
|
||||
|
||||
```text
|
||||
Protocols
|
||||
│
|
||||
Transport Messages
|
||||
│
|
||||
Runtime Commands
|
||||
```
|
||||
|
||||
Каждый уровень отвечает только за собственную область ответственности.
|
||||
|
||||
Это создаёт устойчивый фундамент для следующих Build, в которых будут реализованы Runtime Events, Subscription Manager, Session и механизмы обеспечения надёжности соединения.
|
||||
|
||||
Главный принцип миграции Dzentra остаётся неизменным:
|
||||
|
||||
- архитектура развивается небольшими независимыми шагами;
|
||||
- каждый Build вводит только один новый уровень ответственности;
|
||||
- существующий торговый бот продолжает работать без необходимости полной одномоментной миграции на новую Runtime-подсистему.
|
||||
Reference in New Issue
Block a user