Skip to content

SolitarySpiral/Octamillia

Repository files navigation

Архитектура Octamillia

Статус: В разработке

0.1.6 Добавлена кафка, 2 паралельных вида транспорта сообщений в архитектуре. Тесты pytest не обновлялись. Изменена реализация тентакли brokerage, добавлено сердце, изменена связь мозга с сердцем и транспортом сообщений.


Как с этим работать

  1. Установить базовые параметры используемые в проекте, запустив setup_project.py
  2. Обновить зависимости poetry update
  3. Пример использования архитектуры в main.py запустить из IDE или poetry run python -m main или py main.py
  4. Примеры тентаклей расположены в app.tentacles
  5. Логику самой архитектуры при создании тентаклей менять не нужно.
  6. Если что-то сломалось, посмотри, что написано в setup_project.py
  7. Есть ещё тесты, запускать poetry run pytest -v

Цель: Абсолютная абстракция, объединение архитектур. Мозг - Тело - Щупальца

Мозг(brain) состоит из: WAI, brain, models, external_client. WAI - геном Октамиллиа. brain - мозг архитектуры, оживляет приложение, ищет тентакли, координирует их инициализацию. models - хранит универсальный ответ архитектуры.

Тело(body) состоит из body.

Тентакли(tentacles) состоят из директории с реализацией тентакли и её моделью данных Каждая тентакля создается с использованием следующих классов архитектуры Octamillia

from app.brain import (
    CommandContext,
    CommandDispatchTentacle,
    OctaResponse,
    TentacleMetadata,
)

Тентакля работает со своей моделью данных(Payload) python from .models import ConfigPayload

Тентакля исполняет контракт архитектуры щупальца. class ConfigLoaderStandinTentacle(CommandDispatchTentacle):

Суть контракта:

_COMMAND_HANDLERS = {
        "LOAD_CONFIG": "_load_config",  # Обратите внимание: сохраняем только имя метода
        # ... и так далее
    }

Используется Паттерн Диспетчер Команд (Command Dispatcher) process_command выполняет логику маршрутизации в словарь-диспетчер (Dictionary Dispatch). Возвращает fail если команда такая отсутствует в словаре. Каждая команда становится отдельным, маленьким, легко тестируемым методом с единственной ответственностью.

Метод get_capabilities(self) -> List[str] должен возвращать список доступных команд, которыми оперирует process_command. Он выглядит только так

@classmethod
def get_capabilities(cls) -> List[str]:
    """Метод, который сообщает Мозгу: 'Я умею делать X, Y, Z'."""
    return list(cls._COMMAND_HANDLERS.keys())

Метод get_health(self) -> float возвращает жизнь тентакли.


Планнируемые реализации

  1. Шаблон присоски щупальца(универсальный шаблон для любого микросервиса)
  2. Общение по артериям (обмен данными между микросервисами)
  3. Тело
  4. Пред-жопие
  5. Жопа (база данных)
  6. Интеграция с внешними микросервисами (external_image_tag) или работа с докером.

Принципы SOLID

SOLID — это акроним, представляющий собой пять основных принципов объектно-ориентированного программирования и проектирования, направленных на создание гибких, поддерживаемых и масштабируемых систем.

  • S - Single Responsibility Principle (Принцип Единственной Ответственности) Сущность должна иметь только одну причину для изменения.

Значение: Каждый класс, модуль или функция должен решать только одну задачу.

В Octamillia:

Brain отвечает только за маршрутизацию и реконсиляцию (Control Plane).

CommandDispatchTentacle отвечает только за контракт взаимодействия.

Локальные Payload модели (VideoPayload, ConfigPayload) отвечают только за структуру данных своего домена.


  • O - Open/Closed Principle (Принцип Открытости/Закрытости) Сущности должны быть открыты для расширения, но закрыты для модификации.

Значение: Вы должны иметь возможность добавлять новый функционал, не меняя существующий, протестированный код.

В Octamillia: Чтобы добавить новое щупальце (AudioSync), вам не нужно изменять ядро (Brain, WAI, models.py). Вы просто создаете новый файл с TentacleMetadata и новой логикой, который регистрируется в системе.


  • L - Liskov Substitution Principle (Принцип Подстановки Барбары Лисков) Объекты в программе должны быть заменены экземплярами их подтипов без изменения правильности выполнения программы.

Значение: Наследник должен полностью соответствовать поведению родителя. Если B наследуется от A, то везде, где используется A, можно без проблем использовать B.

В Octamillia: Любой класс, наследующий CommandDispatchTentacle (например, ConfigLoaderStandinTentacle), может быть передан в Brain.route_command, и Мозг будет знать, как с ним работать.


  • I - Interface Segregation Principle (Принцип Разделения Интерфейса) Клиенты не должны зависеть от интерфейсов, которые они не используют.

Значение: Лучше иметь много мелких, специализированных интерфейсов, чем один большой, "жирный".

В Octamillia: Контракт CommandDispatchTentacle содержит минимально необходимый набор методов (process_command, get_health, get_capabilities). Если бы мы добавили туда методы, нужные только для работы с БД, другие щупальца, не использующие БД, были бы вынуждены их реализовывать. В текущей реализации создавать вручную методы process_command и get_capabilities не нужно


  • D - Dependency Inversion Principle (Принцип Инверсии Зависимостей) Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.

Значение: Вместо того чтобы Мозг (высокий уровень) напрямую вызывал конкретный класс (VideoSyncStandinTentacle — низкий уровень), они оба зависят от абстракции (TentacleContract и CommandDispatchTentacle).

В Octamillia: Мозг не знает, как VideoSync выполняет команду (с помощью yt-dlp или другим способом); он знает только, что щупальце контрактно обязано выполнить process_command. Это обеспечивает слабую связанность. В текущей реализации щупальцу не нужно выполнять process_command, оно реализовано в архитектуре CommandDispatchTentacle.


Паттерны и их реализация в Octamillia

Ports and Adapters (Hexagonal Architecture)

Структурный паттерн, который изолирует ядро приложения от внешнего мира через абстрактные порты (интерфейсы). TentacleContract (Порт) — это базовый контракт, а CommandDispatchTentacle (Адаптер) — это конкретная реализация контракта через архитектуру Octamillia.

class ConfigLoaderStandinTentacle(CommandDispatchTentacle) реализует конкретную логику, не смотрит на начинку архитектуры.

Command

Поведенческий паттерн, который инкапсулирует запрос как объект, позволяя параметризовать клиентов различными запросами. Объект CommandContext инкапсулирует команду (command_name), параметры (params) и метаданные для передачи по системе.

Service Locator / Registry

Структурный паттерн, который централизует информацию о доступных сервисах. WAI_REGISTRY и Brain.registry — это централизованный реестр, где регистрируются все TentacleMetadata.

Strategy

Поведенческий паттерн, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Brain.route_command использует стратегию Failover/Round Robin для выбора, какое щупальце будет выполнять команду.

Circuit Breaker (Автоматический Выключатель)

Паттерн отказоустойчивости, который предотвращает каскадные отказы, быстро прерывая вызов к отказавшему сервису. config_breaker (в ConfigLoaderStandinTentacle) защищает Standin от перегрузки, мгновенно прерывая выполнение при многочисленных сбоях.

Round Robin

Алгоритм балансировки нагрузки, который циклически распределяет запросы между доступными серверами. Реализация в Brain.route_command через self.last_used_index для равномерного распределения трафика между здоровыми внешними щупальцами.

Generic Repository

Концепция универсального, типизированного контейнера для данных. Класс OctaResponse[DataT] действует как универсальный "конверт", который может содержать любую типизированную полезную нагрузку (DataT), не зная её структуры заранее.

Идея

Архитектура будет похожа на медузу, либо на осьминога. Пусть будет тело-монолит и 8(а может меньше, не суть) тентаклей. Предположительно тентакли присоединяются к телу через унифицированный интерфейс, который подобный usb. Он и данные, он и зарядка, он методы не знает, но короче как-то монолит узнает, что есть тентакля и сможет ей управлять.

На тентакле есть присоски, каждая присоска может быть отдельным микросервисом. Приходит потребитель, говорит мозгу, что хочу то и сё. Нервная система, отдельная от мозга(а может и нет) хватает тентаклей потребителя и присосками коммуницирует сервисы.

К слову об этих щупальцах, в теории можно горизонтально масштабировать и схватить всех и каждого... и присоединиться присосками каждому по потребностям.

Мозгу и телу не обязательно знать, как дела с щупальцами, они сами по себе. Даже если оторвется, то как бы даже пофиг.

Тентакли растут от тела, а не от головы. К тому же тело под управлением мозга может и сожрать и выделения сделать. А медузы вообще могут отрастить новое тело, если оно оторвалось вместе со всеми конечностями. Не уверен, что наоборот, но мозг не должен решать как надо дышать.

Ещё как вариант, артерии... которые могут пронизывать и мозг и тело и каждую тентаклю. Условно шины взаимодействия исключительно самого тела, раздающее кислород(команды мозга, туловища и нервной системы), а вены - шины ведущие обратно от тентаклей в тело в общую БД для объединения данных от всех микросервисов. Пусть Бд будет "жопа". Её можно отрастить до гигантских размеров, зато не придется делать логику, залезь в бд щупальца, залезь в бд присоски, залезнь в бд ещё куда-нибудь. К слову, об этом. Жопа может быть отдельным модулем, как standby или реплика.

Потребитель обхватывается одним щупальцем. Все сервисы и поток данных в хронологическом порядке идет по одной вене щупальца. Если потребитель почему-то держится сразу двумя щупальцами для распределения нагрузки, условно, то половина данных придет по одному щупальцу, другая отвалится по таймауту, если потребитель вдруг снова держится одной тентаклей. Сломанные операции проходят ретрай по ключу идемпотентности и затем полная картина собирается в пред-жопии, чтобы полноценным фактом записаться в бд жопы.

В щупальце проход по сервисам идет по порядку, да, мы обхватываем щупальцем потребителя несколькими присосками, но если процесс дал сбой, А - успех, Б - Успех, С - поломка, то поломка на присоске С, сразу скажет потребителю, что ты сломался тут, всё. Давай по новой. Да и потребителю будет полезно узнать, если тентакля оторвалась, он сразу увидит полный чек здоровья упадет в 0.

Самое интересное, достаточно в теле (или в голове) создать слой WAI (what am I?) куда положить исходники щупальца, и самих сервисов, Условный git репозиторий, которым щупальца могут отращиваться. Ну или как говорится, абстрактный класс и конкретные реализации. Двухслотовые модули для микросервисов. В первом микросервис говорит, свою спецификацию, во второй кладется его реализация. Это обеспечит самую полную универсальность в принципе. осьминог сможет и реконсиляцию провести и из вк скачать и кофе сварить. Правда я едва ли могу представить архитектуру интерфейса для интерфейсов, в который приживутся любые внешние модули, но ладно. Говоря самым базовым языком, в слое wai эталонная модель щупальца, если осьминожка окажется только с головой и телом, он сможет сделать всё сам без своих конечностей.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages