Перейти к содержанию

Patterns

Архитектурные паттерны, которые применяются в наших сервисах. Каждый — deep-dive: не только «как», но и «почему», «какие trade-off'ы», «когда не использовать».

Reference-правила про Watermill, Kafka и HTTP — в ../conventions/. Страницы здесь отвечают на вопрос «какой архитектурный приём применить для этой задачи».

Страницы

  • outbox.mdTransactional Outbox. Публикация в Kafka идёт в две стадии: запись в таблицу outbox внутри бизнес- транзакции + асинхронный forwarder. Убирает dual-write.
  • cqrs.mdCQRS через watermill/components/cqrs. Типизированные Command/Event handler'ы вместо switch по Event-Type. Lite-вариант, без отдельных read-моделей.
  • idempotent-consumer.mdIdempotent Consumer. Защита от at-least-once дублей Kafka: middleware.Deduplicator поверх Redis + идемпотентность на БД-уровне.
  • api-composition.mdAPI Composition. Склейка данных из нескольких сервисов для list-view; без shared database и cross-service JOIN. Timeouts, partial failure, N+1.
  • retry-and-circuit-breaker.mdRetry + 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-события.