Patterns¶
Архитектурные паттерны, которые применяются в наших сервисах. Каждый — deep-dive: не только «как», но и «почему», «какие trade-off'ы», «когда не использовать».
Reference-правила про Watermill, Kafka и HTTP — в
../conventions/. Страницы здесь отвечают на
вопрос «какой архитектурный приём применить для этой задачи».
Страницы¶
outbox.md— Transactional Outbox. Публикация в Kafka идёт в две стадии: запись в таблицу outbox внутри бизнес- транзакции + асинхронный forwarder. Убирает dual-write.cqrs.md— CQRS черезwatermill/components/cqrs. Типизированные Command/Event handler'ы вместоswitchпоEvent-Type. Lite-вариант, без отдельных read-моделей.idempotent-consumer.md— Idempotent Consumer. Защита от at-least-once дублей Kafka:middleware.Deduplicatorповерх Redis + идемпотентность на БД-уровне.api-composition.md— API Composition. Склейка данных из нескольких сервисов для list-view; без shared database и cross-service JOIN. Timeouts, partial failure, N+1.retry-and-circuit-breaker.md— Retry + Circuit Breaker. Как повторять запросы к downstream и когда «размыкать цепь», чтобы не добивать уже лежащий сервис. Exponential backoff + jitter, идемпотентность как условие, fallback стратегии.
Когда использовать какой¶
| Задача | Паттерн |
|---|---|
| Публикация события в Kafka из бизнес-операции | outbox.md |
| Consumer принимает событие и меняет БД | idempotent-consumer.md (вместе с outbox на publisher-стороне) |
| В сервисе > 3 команд/событий на одну доменную модель | cqrs.md |
| Нужно отдать UI-клиенту данные из 2+ сервисов одним ответом | api-composition.md |
| Внешний сервис / БД / Redis периодически падает, нужна защита от transient-ошибок и каскадного падения | retry-and-circuit-breaker.md |
Если задача не попадает ни в одну колонку — скорее всего, паттерн здесь не нужен. Не подключай CQRS «на вырост», не заводи outbox без Kafka-события.