build 059.11: add runtime command models
This commit is contained in:
82
app/src/market_data/acquisition/runtime/runtime_commands.py
Normal file
82
app/src/market_data/acquisition/runtime/runtime_commands.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# app/src/market_data/acquisition/runtime/runtime_commands.py
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from src.market_data.acquisition.runtime.transport_messages import (
|
||||||
|
TransportBinaryMessage,
|
||||||
|
TransportTextMessage,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
TransportMessage = TransportTextMessage | TransportBinaryMessage
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ConnectCommand:
|
||||||
|
"""
|
||||||
|
Команда на открытие транспортного соединения.
|
||||||
|
|
||||||
|
Команда выражает намерение Runtime и не выполняет подключение
|
||||||
|
самостоятельно.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class DisconnectCommand:
|
||||||
|
"""
|
||||||
|
Команда на закрытие транспортного соединения.
|
||||||
|
|
||||||
|
Команда не содержит сетевой логики и не управляет транспортом
|
||||||
|
самостоятельно.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class SubscribeCommand:
|
||||||
|
"""
|
||||||
|
Команда на регистрацию и отправку транспортной подписки.
|
||||||
|
|
||||||
|
subscription_key является стабильным идентификатором подписки,
|
||||||
|
используемым будущим Subscription Manager.
|
||||||
|
|
||||||
|
message содержит уже подготовленный транспортный payload.
|
||||||
|
Runtime не интерпретирует его содержимое.
|
||||||
|
"""
|
||||||
|
|
||||||
|
subscription_key: str
|
||||||
|
message: TransportMessage
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class UnsubscribeCommand:
|
||||||
|
"""
|
||||||
|
Команда на удаление и отправку отмены транспортной подписки.
|
||||||
|
|
||||||
|
subscription_key связывает отмену с ранее зарегистрированной
|
||||||
|
подпиской.
|
||||||
|
|
||||||
|
message содержит уже подготовленный транспортный payload.
|
||||||
|
"""
|
||||||
|
|
||||||
|
subscription_key: str
|
||||||
|
message: TransportMessage
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class SendTextCommand:
|
||||||
|
"""
|
||||||
|
Команда на отправку текстового транспортного сообщения.
|
||||||
|
"""
|
||||||
|
|
||||||
|
message: TransportTextMessage
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class SendBinaryCommand:
|
||||||
|
"""
|
||||||
|
Команда на отправку бинарного транспортного сообщения.
|
||||||
|
"""
|
||||||
|
|
||||||
|
message: TransportBinaryMessage
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# app/tests/unit/market_data/acquisition/runtime/test_runtime_commands.py
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import FrozenInstanceError
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.market_data.acquisition.runtime.runtime_commands import (
|
||||||
|
ConnectCommand,
|
||||||
|
DisconnectCommand,
|
||||||
|
SendBinaryCommand,
|
||||||
|
SendTextCommand,
|
||||||
|
SubscribeCommand,
|
||||||
|
UnsubscribeCommand,
|
||||||
|
)
|
||||||
|
from src.market_data.acquisition.runtime.transport_messages import (
|
||||||
|
TransportBinaryMessage,
|
||||||
|
TransportTextMessage,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_command_is_marker_command() -> None:
|
||||||
|
assert ConnectCommand() == ConnectCommand()
|
||||||
|
|
||||||
|
|
||||||
|
def test_disconnect_command_is_marker_command() -> None:
|
||||||
|
assert DisconnectCommand() == DisconnectCommand()
|
||||||
|
|
||||||
|
|
||||||
|
def test_subscribe_command_contains_subscription_key_and_text_message() -> None:
|
||||||
|
message = TransportTextMessage(payload='{"action":"subscribe"}')
|
||||||
|
command = SubscribeCommand(
|
||||||
|
subscription_key="quotes:BTCUSDT",
|
||||||
|
message=message,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert command.subscription_key == "quotes:BTCUSDT"
|
||||||
|
assert command.message is message
|
||||||
|
|
||||||
|
|
||||||
|
def test_subscribe_command_supports_binary_message() -> None:
|
||||||
|
message = TransportBinaryMessage(payload=b"\x01\x02")
|
||||||
|
command = SubscribeCommand(
|
||||||
|
subscription_key="binary:market-data",
|
||||||
|
message=message,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert command.message is message
|
||||||
|
|
||||||
|
|
||||||
|
def test_unsubscribe_command_contains_subscription_key_and_message() -> None:
|
||||||
|
message = TransportTextMessage(payload='{"action":"unsubscribe"}')
|
||||||
|
command = UnsubscribeCommand(
|
||||||
|
subscription_key="quotes:BTCUSDT",
|
||||||
|
message=message,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert command.subscription_key == "quotes:BTCUSDT"
|
||||||
|
assert command.message is message
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_text_command_contains_transport_text_message() -> None:
|
||||||
|
message = TransportTextMessage(payload="ping")
|
||||||
|
command = SendTextCommand(message=message)
|
||||||
|
|
||||||
|
assert command.message is message
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_binary_command_contains_transport_binary_message() -> None:
|
||||||
|
message = TransportBinaryMessage(payload=b"\x00")
|
||||||
|
command = SendBinaryCommand(message=message)
|
||||||
|
|
||||||
|
assert command.message is message
|
||||||
|
|
||||||
|
|
||||||
|
def test_subscribe_command_is_immutable() -> None:
|
||||||
|
command = SubscribeCommand(
|
||||||
|
subscription_key="quotes:BTCUSDT",
|
||||||
|
message=TransportTextMessage(payload="subscribe"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(FrozenInstanceError):
|
||||||
|
setattr(command, "subscription_key", "quotes:ETHUSDT")
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_text_command_is_immutable() -> None:
|
||||||
|
command = SendTextCommand(
|
||||||
|
message=TransportTextMessage(payload="ping"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(FrozenInstanceError):
|
||||||
|
setattr(
|
||||||
|
command,
|
||||||
|
"message",
|
||||||
|
TransportTextMessage(payload="pong"),
|
||||||
|
)
|
||||||
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