Показаны сообщения с ярлыком Qwen. Показать все сообщения
Показаны сообщения с ярлыком Qwen. Показать все сообщения

пятница, 18 сентября 2026 г.

Qwen, Aspire, Gateway, Http

Qwen, Aspire, Gateway, Http

https://chat.qwen.ai/s/75eecb49-01e6-446f-8953-2f35f9d9d9b8?fev=0.2.91

https://chat.qwen.ai/s/75eecb49-01e6-446f-8953-2f35f9d9d9b8?fev=0.2.91

Ниже — честный черновик описания системы в формате обсуждения. Я заполняю только то, что реально подтверждается вашими диалогами и кодом из Trading.txt. Там, где фактов нет, я прямо пишу: «пропускаю» или «нет данных».
Важная оговорка: сейчас это не продакшен-система, а архитектурный прототип / каркас. Поэтому многие пункты про KPI, экономику, эксплуатацию и отзывы пользователей заполнить без выдумок нельзя.

Сводная таблица: «Как было / Как задумывалось / Что получили»

Аспект
Как было / типовой Status Quo
Как задумывалось
Что реально получили сейчас
Взаимодействие сервисов
Прямые связи сервисов, либо избыточные RabbitMQ / MassTransit / Kafka
Уйти от N × N-спагетти к модели Сервисы ↔ Router ↔ Сервисы
Есть цепочка: Trading.Web -> Trading.Gateway -> Trading.Api.Orders / Trading.Api.MarketData
Топология системы
Неявные зависимости, скрытые HttpClient, магические URL
AppHost как «живой манифест» и «код как конституция»
В Trading.AppHost/Program.cs явно задано: web знает только gateway, gateway знает orders-api и market-data-api
Маршрутизация
Ручные адреса, порты, конфиги, потенциальный хаос
Централизованный маршрутизатор на HTTP/URI
Trading.Gateway использует YARP + AddServiceDiscoveryDestinationResolver()
Наблюдаемость
Разрозненные логи, трейсы надо специально связывать
Единый «радар» через Aspire Dashboard + OpenTelemetry
Подключен Trading.ServiceDefaults, есть MapDefaultEndpoints(), здоровье, трейсинг, логи через Aspire
Изоляция фронтенда
Фронтенд может ходить во все сервисы напрямую
Фронтенд должен видеть только Gateway
В Trading.Web/Program.cs клиент настроен на http://gateway, прямых ссылок на orders-api / market-data-api нет
Надежность мутаций
Либо прямой HTTP с рисками, либо сразу тяжелый брокер
Позже добавить Outbox / Wolverine / «почтовый ящик»
Пока только прямой HTTP и базовая resilience из ServiceDefaults; Outbox еще нет
Контракты
Дублирование DTO в разных проектах
Общий контрактный слой
Пока контракты дублируются: Order есть в Trading.Api.Orders и в Trading.Web/TradingApiClient.cs
Бизнес-данные
Либо полноценная БД, либо заглушки
Начать с простого прототипа
Данные пока in-memory: список ордеров и словарь рыночных цен

1. Контекст и отправная точка

Бизнес-проблема

В предоставленных материалах нет описания конкретной старой бизнес-системы, поэтому честно можно сказать так:
Исходная боль — не конкретный легаси-продукт, а архитектурная проблема построения взаимодействия между проектами внутри .NET Aspire без избыточного усложнения.
Основная боль, которую видно из диалогов:
  • сервисов становится больше;
  • прямые связи превращаются в спагетти N × N;
  • разработчики начинают добавлять RabbitMQ / MassTransit / Kafka туда, где это пока не нужно;
  • архитектура становится неявной;
  • связи существуют не как закон, а как договоренность;
  • сложно понять, кто кого вызывает, где падает запрос и почему система деградирует.
Если формулировать коротко:
Нужно было сделать взаимодействие между Aspire-проектами простым, наблюдаемым, управляемым и не превращающимся в хаос.

Существующее решение

Если считать «старым» типовой подход, который обсуждался, то он выглядел примерно так:
  • каждый сервис может напрямую вызывать другой сервис;
  • для асинхронности сразу добавляется RabbitMQ / Kafka / MassTransit;
  • фронтенд может ходить в несколько backend-сервисов напрямую;
  • топология существует в голове разработчиков или в устаревших схемах;
  • наблюдаемость приходится отдельно склеивать логами, трейсами и метриками.
В текущем репозитории уже использованы:
  • .NET 10;
  • Aspire.Hosting / Aspire.AppHost.Sdk 13.4.6;
  • ASP.NET Core;
  • YARP Reverse Proxy 2.3.0;
  • Microsoft.Extensions.ServiceDiscovery.Yarp 10.0.0;
  • OpenTelemetry;
  • Blazor Web / Interactive Server;
  • Trading.ServiceDefaults как общий слой для здоровья, телеметрии и resilience.

Критические недостатки старого подхода

Из диалогов и архитектурного смысла следуют такие недостатки:
  1. Спагетти-связи

ServiceA -> ServiceB ServiceB -> ServiceC ServiceC -> ServiceA ServiceD -> ServiceB ...
При росте числа сервисов система становится непонятной.
  1. Избыточная инфраструктура Например:
csharp
только для того, чтобы два сервиса могли обмениваться простыми сообщениями.
  1. Неявная топология Разработчик может написать прямой HttpClient-вызов, и это не будет видно из манифеста архитектуры.
  2. Отсутствие физического контроля связей В старой модели безопасность и границы контролируются договоренностями, код-ревью или внешними сетевыми политиками.
  3. Плохая наблюдаемость сквозных сценариев Если запрос идет через несколько сервисов, без единого трейса сложно понять, где именно проблема.

Ограничения среды

Конкретных данных нет:
  • бюджет: пропускаю;
  • регуляторные требования: пропускаю;
  • требования к унаследованным данным: пропускаю;
  • ограничения по команде и срокам: пропускаю.
Но можно указать качественное ограничение:
Система начиналась как локальный / экспериментальный Aspire-прототип, поэтому нужно было избежать тяжелых внешних зависимостей вроде RabbitMQ, Kafka, отдельного Service Mesh и сложной инфраструктуры.

2. Концепция и цели

Формулировка гипотезы

Главная гипотеза проекта:
Если ввести центральный Gateway как полноценный Aspire-проект и задать все связи через AppHost, то архитектура станет управляемой, наблюдаемой и защищенной от случайного усложнения.
Более точная формулировка:
Если фронтенд будет обращаться только к Gateway, а Gateway будет единственным маршрутизатором к бизнес-сервисам, то система перейдет от хаотичной модели N × N к управляемой модели Hub-and-Spoke.
Или совсем коротко:
Архитектура должна быть не диаграммой в документации, а исполняемым законом среды.

Ключевые метрики успеха

Фактических производственных метрик пока нет, поэтому конкретные цифры по задержкам, памяти, нагрузке и конверсии я пропускаю.
Но уже можно зафиксировать структурные показатели, которые подтверждают архитектурный результат.
Например:
Показатель
Значение / факт
Количество бизнес-сервисов, доступных фронтенду напрямую
0
Единственная точка входа для фронтенда
gateway
Количество бизнес-сервисов, известных фронтенду
1: gateway
Количество backend-сервисов, известных Gateway
2: orders-api, market-data-api
Количество маршрутов в YARP
4
Количество кластеров в YARP
2
Наличие сквозного трейса через Aspire
потенциально есть, через ServiceDefaults и OpenTelemetry
Наличие health-эндпоинтов
есть через MapDefaultEndpoints()
Для будущего обсуждения можно предложить такие KPI:
  • время обнаружения причины сбоя по трейсу;
  • количество прямых зависимостей между бизнес-сервисами;
  • число вызовов фронтенда к внутренним сервисам в обход Gateway;
  • средняя задержка запроса через Gateway;
  • процент успешных запросов;
  • количество ошибок 5xx на маршрутах;
  • время онбординга нового разработчика до понимания топологии системы.
Но реальных цифр пока нет.

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

Из диалогов видно, что рассматривались разные варианты.

1. RabbitMQ / MassTransit

Почему отложили:
  • избыточно для простых внутренних взаимодействий;
  • добавляет инфраструктурную сложность;
  • появляется очередь, обменники, дедупликация, идемпотентность;
  • для сценария «сервис А вызывает сервис Б» это часто слишком много.

2. NATS

Почему рассматривался:
  • легкий брокер;
  • высокая скорость;
  • хорошо подходит для Pub/Sub.
Почему пока не выбран:
  • все равно появляется отдельный инфраструктурный компонент;
  • на первом этапе проще проверить модель через HTTP.

3. SignalR для server-to-server

Почему рассматривался:
  • удобен для push-доставки;
  • хорош для клиентских обновлений.
Почему не подходит как основной транспорт между сервисами:
  • нет гарантий доставки как у очереди;
  • при падении получателя сообщения могут теряться;
  • масштабирование сложнее;
  • лучше подходит для связи сервер -> клиент, а не сервис -> сервис.

4. Распределенный MediatR

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

5. WolverineFx

Почему рассматривался:
  • «умный» аналог MediatR;
  • умеет локальный и распределенный вызов;
  • имеет паттерн Outbox;
  • хорошо подходит для надежной асинхронной доставки.
Почему пока не внедрен:
  • это уже следующий уровень сложности;
  • сначала нужно закрепить простой и понятный HTTP-каркас;
  • пока нет реальной потребности в гарантированной асинхронной федерации.

6. Модульный монолит

Почему рассматривался:
  • минимум сетевой сложности;
  • максимальная скорость;
  • простая отладка.
Почему не выбран как текущая основа:
  • проект уже ориентирован на распределенные сервисы;
  • интересна именно модель управляемой федерации сервисов под Aspire.

Границы проекта

На текущем этапе намеренно решили не делать:
  • полноценную базу данных;
  • аутентификацию и авторизацию;
  • риск-менеджмент;
  • реальный matching engine;
  • стаканы ордеров;
  • Outbox / транзакционную доставку;
  • Wolverine;
  • RabbitMQ / Kafka;
  • SignalR;
  • интеграционные тесты;
  • CI/CD;
  • production-деплой;
  • идемпотентность команд;
  • версионирование контрактов;
  • общий проект контрактов;
  • нагрузочное тестирование.
Это правильно, потому что проект находится на этапе проверки архитектурной идеи.

3. Инновационность и новизна

Относительно рынка

Сами технологии не являются уникальными:
  • YARP существует;
  • Aspire существует;
  • OpenTelemetry существует;
  • HTTP как транспорт существует давно;
  • паттерн API Gateway известен;
  • BFF известен;
  • Hub-and-Spoke известен.
Новизна здесь не в одной технологии, а в их комбинации и архитектурной философии.
Ключевая новизна:
.NET Aspire AppHost используется не просто как лаунчер, а как исполняемый конституционный закон топологии системы.
Или:
Архитектура становится не документацией, а средой исполнения, которая физически мешает сделать неправильную связь.