588 lines
13 KiB
Markdown
588 lines
13 KiB
Markdown
# Build 059.12 — Runtime Event Models
|
||
|
||
**Migration Build**
|
||
|
||
---
|
||
|
||
# Цель Build
|
||
|
||
После завершения Build 059.11 Runtime уже содержит три независимых архитектурных уровня:
|
||
|
||
- Runtime Protocols;
|
||
- Runtime Transport Messages;
|
||
- Runtime Commands.
|
||
|
||
Следующим шагом является создание слоя **Runtime Events**.
|
||
|
||
Данный Build вводит immutable-модели событий Runtime.
|
||
|
||
События описывают **уже произошедшие факты** и полностью отделены от команд Runtime.
|
||
|
||
---
|
||
|
||
# Причина появления Runtime Events
|
||
|
||
До настоящего момента Runtime умел описывать:
|
||
|
||
- транспортные интерфейсы;
|
||
- транспортные сообщения;
|
||
- намерения системы.
|
||
|
||
Однако отсутствовал механизм описания результатов выполнения этих намерений.
|
||
|
||
Например.
|
||
|
||
После выполнения
|
||
|
||
```
|
||
ConnectCommand
|
||
```
|
||
|
||
может произойти:
|
||
|
||
```
|
||
ConnectedEvent
|
||
```
|
||
|
||
или
|
||
|
||
```
|
||
ConnectFailedEvent
|
||
```
|
||
|
||
Это два разных факта.
|
||
|
||
Команда выражает желание выполнить действие.
|
||
|
||
Событие фиксирует результат выполнения этого действия.
|
||
|
||
---
|
||
|
||
# Архитектурная идея
|
||
|
||
Build 059.12 завершает построение базовой event-driven модели Runtime.
|
||
|
||
Получается следующая архитектура.
|
||
|
||
```text
|
||
Runtime
|
||
|
||
Commands
|
||
│
|
||
▼
|
||
Session
|
||
│
|
||
▼
|
||
Transport
|
||
│
|
||
▼
|
||
Events
|
||
```
|
||
|
||
Commands направляются вниз.
|
||
|
||
Events распространяются вверх.
|
||
|
||
Именно такое разделение используется в большинстве современных event-driven систем.
|
||
|
||
---
|
||
|
||
# Новый модуль
|
||
|
||
Создан файл
|
||
|
||
```
|
||
src/market_data/acquisition/runtime/runtime_events.py
|
||
```
|
||
|
||
В модуле определены immutable-модели Runtime Events.
|
||
|
||
---
|
||
|
||
# Использование Transport Messages
|
||
|
||
Транспортные события используют модели Build 059.10.
|
||
|
||
```
|
||
TransportTextMessage
|
||
TransportBinaryMessage
|
||
```
|
||
|
||
Runtime Event не знает содержимого сообщения.
|
||
|
||
Он лишь фиксирует факт передачи или получения транспортного payload.
|
||
|
||
---
|
||
|
||
# TransportMessage
|
||
|
||
Для удобства типизации используется локальный alias.
|
||
|
||
```python
|
||
TransportMessage =
|
||
TransportTextMessage
|
||
| TransportBinaryMessage
|
||
```
|
||
|
||
Он используется только внутри Runtime Events.
|
||
|
||
Никакой новой модели данных не создаётся.
|
||
|
||
---
|
||
|
||
# Новые события
|
||
|
||
Build вводит девять Runtime Events.
|
||
|
||
---
|
||
|
||
# ConnectedEvent
|
||
|
||
Фиксирует успешное открытие транспортного соединения.
|
||
|
||
Событие является маркерным.
|
||
|
||
Не содержит дополнительных данных.
|
||
|
||
Причина.
|
||
|
||
На текущем этапе Runtime отсутствует модель идентификатора соединения.
|
||
|
||
Добавлять подобные поля преждевременно.
|
||
|
||
---
|
||
|
||
# DisconnectedEvent
|
||
|
||
Фиксирует завершение транспортного соединения.
|
||
|
||
Событие также является маркерным.
|
||
|
||
Причина отключения намеренно отсутствует.
|
||
|
||
Определение причин разрыва соединения относится к будущему уровню Reliability.
|
||
|
||
---
|
||
|
||
# ConnectFailedEvent
|
||
|
||
Фиксирует неудачную попытку подключения.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
reason
|
||
```
|
||
|
||
Причина хранится в виде строки.
|
||
|
||
---
|
||
|
||
## Почему используется строка
|
||
|
||
Во время проектирования рассматривались варианты хранения:
|
||
|
||
- Exception;
|
||
- traceback;
|
||
- transport-specific error;
|
||
- websocket exception.
|
||
|
||
От данных вариантов было принято решение отказаться.
|
||
|
||
Runtime Event не должен зависеть от конкретной реализации транспорта.
|
||
|
||
Строковое описание полностью соответствует принципу transport-agnostic Runtime.
|
||
|
||
---
|
||
|
||
# MessageReceivedEvent
|
||
|
||
Фиксирует получение транспортного сообщения.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
TransportMessage
|
||
```
|
||
|
||
Runtime Event не анализирует payload.
|
||
|
||
Его обработкой занимаются последующие уровни Acquisition.
|
||
|
||
---
|
||
|
||
# MessageSentEvent
|
||
|
||
Фиксирует успешную передачу транспортного сообщения.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
TransportMessage
|
||
```
|
||
|
||
Это позволяет журналировать транспортный обмен, не анализируя содержимое сообщений.
|
||
|
||
---
|
||
|
||
# ReconnectStartedEvent
|
||
|
||
Фиксирует начало новой попытки восстановления соединения.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
attempt
|
||
```
|
||
|
||
---
|
||
|
||
## Почему хранится номер попытки
|
||
|
||
Номер попытки является устойчивым Runtime-фактом.
|
||
|
||
Он потребуется:
|
||
|
||
- Supervisor;
|
||
- журналированию;
|
||
- диагностике;
|
||
- мониторингу Runtime.
|
||
|
||
---
|
||
|
||
# ReconnectCompletedEvent
|
||
|
||
Фиксирует успешное восстановление соединения.
|
||
|
||
Также содержит:
|
||
|
||
```
|
||
attempt
|
||
```
|
||
|
||
что позволяет определить, на какой попытке произошло восстановление.
|
||
|
||
---
|
||
|
||
# ReconnectFailedEvent
|
||
|
||
Фиксирует завершение очередной попытки восстановления соединения с ошибкой.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
attempt
|
||
reason
|
||
```
|
||
|
||
Таким образом Runtime может описывать процесс восстановления без зависимости от конкретной реализации транспорта.
|
||
|
||
---
|
||
|
||
# HeartbeatTimeoutEvent
|
||
|
||
Фиксирует превышение допустимого интервала heartbeat.
|
||
|
||
Содержит:
|
||
|
||
```
|
||
timeout_seconds
|
||
```
|
||
|
||
Хранится только настроенный порог ожидания.
|
||
|
||
---
|
||
|
||
## Почему отсутствуют timestamp
|
||
|
||
Во время проектирования обсуждалось хранение:
|
||
|
||
```
|
||
timestamp
|
||
occurred_at
|
||
created_at
|
||
```
|
||
|
||
Было принято решение отказаться.
|
||
|
||
Причины.
|
||
|
||
---
|
||
|
||
### Причина №1
|
||
|
||
В Runtime ещё отсутствует единая модель времени.
|
||
|
||
---
|
||
|
||
### Причина №2
|
||
|
||
В разных окружениях время может поступать из различных источников.
|
||
|
||
Например:
|
||
|
||
- системные часы;
|
||
- монотонные часы;
|
||
- серверное время биржи.
|
||
|
||
До появления общей модели времени вводить timestamp преждевременно.
|
||
|
||
---
|
||
|
||
# Почему отсутствует RuntimeEvent
|
||
|
||
Также обсуждалось создание общего базового класса.
|
||
|
||
Например.
|
||
|
||
```
|
||
RuntimeEvent
|
||
```
|
||
|
||
или
|
||
|
||
```
|
||
BaseEvent
|
||
```
|
||
|
||
От идеи отказались.
|
||
|
||
Причины.
|
||
|
||
---
|
||
|
||
## Причина №1
|
||
|
||
Все события являются immutable dataclass.
|
||
|
||
Общего поведения между ними нет.
|
||
|
||
---
|
||
|
||
## Причина №2
|
||
|
||
Преждевременная иерархия только усложняет архитектуру.
|
||
|
||
---
|
||
|
||
## Причина №3
|
||
|
||
Общий базовый тип можно добавить позднее без нарушения обратной совместимости.
|
||
|
||
---
|
||
|
||
# Почему отсутствует RuntimeEventType
|
||
|
||
Рассматривалось использование enum.
|
||
|
||
Например.
|
||
|
||
```
|
||
CONNECTED
|
||
DISCONNECTED
|
||
MESSAGE_RECEIVED
|
||
```
|
||
|
||
Было принято решение отказаться.
|
||
|
||
Тип события полностью определяется его классом.
|
||
|
||
Дополнительный enum создавал бы дублирование информации.
|
||
|
||
---
|
||
|
||
# Почему отсутствуют Subscription Events
|
||
|
||
Изначально предполагалось добавить:
|
||
|
||
- SubscriptionRegisteredEvent;
|
||
- SubscriptionRemovedEvent;
|
||
- SubscriptionRestoredEvent.
|
||
|
||
После анализа архитектуры было принято решение перенести их в следующий Build.
|
||
|
||
Причина.
|
||
|
||
В Build 059.12 Subscription Manager ещё отсутствует.
|
||
|
||
Следовательно, пока отсутствует компонент, способный генерировать подобные события.
|
||
|
||
События должны появляться одновременно с соответствующим уровнем архитектуры.
|
||
|
||
Поэтому Subscription Events перенесены в Build 059.13.
|
||
|
||
---
|
||
|
||
# Что НЕ входит в Build
|
||
|
||
Сознательно не реализованы:
|
||
|
||
- Event Bus;
|
||
- Dispatcher;
|
||
- Observer;
|
||
- callbacks;
|
||
- asyncio;
|
||
- Publisher;
|
||
- Subscriber;
|
||
- Session;
|
||
- Subscription Manager;
|
||
- обработчики событий;
|
||
- очередь событий.
|
||
|
||
Build содержит исключительно immutable-модели Runtime Events.
|
||
|
||
---
|
||
|
||
# Обновлённая архитектура Runtime
|
||
|
||
После завершения Build Runtime приобретает следующий вид.
|
||
|
||
```text
|
||
Runtime
|
||
|
||
Protocols
|
||
│
|
||
Transport Messages
|
||
│
|
||
Runtime Commands
|
||
│
|
||
Runtime Events
|
||
│
|
||
Transport
|
||
│
|
||
Network
|
||
```
|
||
|
||
Каждый уровень отвечает только за собственную область ответственности.
|
||
|
||
---
|
||
|
||
# Следующие Build
|
||
|
||
## Build 059.13
|
||
|
||
Subscription Manager.
|
||
|
||
Появятся:
|
||
|
||
- управление подписками;
|
||
- хранение Runtime-состояния;
|
||
- восстановление подписок;
|
||
- SubscriptionRegisteredEvent;
|
||
- SubscriptionRemovedEvent;
|
||
- SubscriptionRestoredEvent.
|
||
|
||
---
|
||
|
||
## Build 059.14
|
||
|
||
WebSocket Session.
|
||
|
||
Появится координация:
|
||
|
||
- Commands;
|
||
- Events;
|
||
- Transport;
|
||
- Subscription Manager.
|
||
|
||
---
|
||
|
||
## Build 059.15
|
||
|
||
Runtime Reliability.
|
||
|
||
Будут реализованы:
|
||
|
||
- Heartbeat;
|
||
- Reconnect;
|
||
- Supervisor;
|
||
- Scheduler;
|
||
- Ping/Pong.
|
||
|
||
---
|
||
|
||
# Проверка Build
|
||
|
||
Выполнена полная проверка.
|
||
|
||
---
|
||
|
||
## Компиляция
|
||
|
||
```
|
||
python -m compileall
|
||
```
|
||
|
||
Успешно.
|
||
|
||
---
|
||
|
||
## Unit Tests
|
||
|
||
Созданы тесты:
|
||
|
||
```
|
||
test_runtime_events.py
|
||
```
|
||
|
||
Проверяется:
|
||
|
||
- создание каждого события;
|
||
- корректность хранения данных;
|
||
- поддержка TransportMessage;
|
||
- immutable-поведение dataclass.
|
||
|
||
Все тесты успешно пройдены.
|
||
|
||
---
|
||
|
||
## Runtime Regression
|
||
|
||
Совместно проверены:
|
||
|
||
- Runtime Protocols;
|
||
- Runtime Transport Messages;
|
||
- Runtime Commands;
|
||
- Runtime Events.
|
||
|
||
Все Runtime-тесты успешно завершены.
|
||
|
||
---
|
||
|
||
## Проверка репозитория
|
||
|
||
Выполнен
|
||
|
||
```
|
||
git diff --check
|
||
```
|
||
|
||
Ошибок форматирования не обнаружено.
|
||
|
||
---
|
||
|
||
# Итог
|
||
|
||
Build 059.12 завершает формирование слоя Runtime Events.
|
||
|
||
Теперь Runtime имеет четыре полностью независимых уровня.
|
||
|
||
```text
|
||
Protocols
|
||
│
|
||
Transport Messages
|
||
│
|
||
Runtime Commands
|
||
│
|
||
Runtime Events
|
||
```
|
||
|
||
Каждый уровень описывает собственную область ответственности.
|
||
|
||
Commands выражают намерения системы.
|
||
|
||
Events фиксируют уже произошедшие факты.
|
||
|
||
Подобное разделение делает архитектуру Runtime предсказуемой, расширяемой и соответствует общепринятым принципам построения event-driven систем.
|
||
|
||
Следующий Build посвящён созданию Subscription Manager, который станет первым Runtime-компонентом, использующим одновременно Commands и Events, сохраняя при этом независимость транспортного уровня от бизнес-логики Acquisition. |