84 lines
4.2 KiB
Markdown
84 lines
4.2 KiB
Markdown
# ADR-0001: Vertical Slice Architecture, Native AOT, BackgroundService и Aspire
|
||
|
||
## Status
|
||
|
||
**Accepted** — 2026-04-03
|
||
|
||
## Context
|
||
|
||
GM-Relay — Telegram-бот для автоматизации игровых сессий, развёрнутый на Raspberry Pi (ARM64) за NAT.
|
||
Требования к стеку:
|
||
|
||
- **.NET 10 / C# 14** — целевой рантайм.
|
||
- **Native AOT** — минимальный размер бинарника, мгновенный cold start на ARM64.
|
||
- **Raspberry Pi 5** — ограниченные ресурсы (4–8 ГБ RAM).
|
||
- **Long Polling** — Pi за NAT, webhook невозможен без проброса портов.
|
||
|
||
Необходимо выбрать: архитектурный паттерн, планировщик задач, ORM и оркестрацию.
|
||
|
||
## Decision
|
||
|
||
### 1. Vertical Slice Architecture (VSA)
|
||
|
||
Каждый use case реализован как **вертикальный срез**: Command/Query record + Handler.
|
||
Handler содержит всю логику (SQL, Telegram API, валидацию) — без абстрактных репозиториев и сервисных слоёв.
|
||
|
||
**Почему не Clean Architecture:**
|
||
- Бот с 5–7 use cases не нуждается в 4+ проектах и абстракциях.
|
||
- Все зависимости (Npgsql, Telegram.Bot) стабильны — заменять их не планируется.
|
||
- VSA позволяет добавлять фичи без рефакторинга существующих.
|
||
|
||
### 2. BackgroundService + PeriodicTimer (вместо Quartz.NET)
|
||
|
||
Два триггера расписания (T-24ч: подтверждение, T-5мин: ссылка) реализованы через
|
||
`BackgroundService` с `PeriodicTimer(TimeSpan.FromMinutes(1))`.
|
||
|
||
**Stateless-дизайн:** сервис при каждом тике делает SELECT к PostgreSQL, обрабатывает
|
||
найденные сессии и обновляет статус в БД. При перезагрузке — ничего не теряется.
|
||
|
||
**Почему не Quartz.NET:**
|
||
- Quartz.NET **не совместим с Native AOT** (reflection-based job loading).
|
||
- Для двух простых WHERE-запросов Quartz — overkill.
|
||
- BackgroundService нативно поддерживается .NET и AOT.
|
||
|
||
### 3. Npgsql + Dapper.AOT (вместо EF Core)
|
||
|
||
EF Core 10 **не совместим с Native AOT** (reflection-heavy query pipeline, dynamic IL).
|
||
Npgsql ADO.NET — полностью AOT-совместим. Dapper.AOT использует source generators
|
||
для compile-time генерации маппинга.
|
||
|
||
Миграции — **DbUp** (embedded SQL scripts).
|
||
|
||
### 4. Aspire 13 для оркестрации
|
||
|
||
Aspire обеспечивает:
|
||
- Автоматический запуск PostgreSQL в dev-среде.
|
||
- Service discovery и передачу connection strings.
|
||
- OpenTelemetry (traces, metrics, logs) из коробки.
|
||
- Aspire Dashboard для мониторинга.
|
||
|
||
### 5. Telegram.Bot 22.x + Long Polling
|
||
|
||
- Long Polling — единственный вариант для Pi за NAT.
|
||
- Telegram.Bot поддерживает `System.Text.Json` source generators для AOT.
|
||
|
||
## Consequences
|
||
|
||
### Положительные
|
||
|
||
- **Один бинарник ~15–30 МБ** для ARM64 (Native AOT, self-contained).
|
||
- **Мгновенный cold start** (~50ms) на Raspberry Pi.
|
||
- **Простота**: каждая фича — один файл, один handler.
|
||
- **Устойчивость к перезагрузкам**: stateless scheduler + PostgreSQL.
|
||
|
||
### Отрицательные
|
||
|
||
- **Ручной SQL**: нет автогенерации запросов, миграции пишутся руками.
|
||
- **Нет LINQ-to-SQL**: все запросы — строки, ошибки только в runtime.
|
||
- **DI без reflection**: все handlers регистрируются явно (без assembly scanning).
|
||
|
||
### Риски
|
||
|
||
- Dapper.AOT — относительно молодой проект; при проблемах — fallback на чистый Npgsql.
|
||
- Telegram.Bot AOT-совместимость может потребовать кастомного `JsonSerializerContext`.
|