Software Architect · Модуль 12

Синхронность даёт простую ментальную модель. Асинхронность даёт устойчивость и развязку, но требует новых гарантий.

Queue · event · outbox · backpressure · retry

§ 01

Выбор sync или async — это выбор между немедленным ответом и устойчивой обработкой во времени.

Синхронный вызов подходит для вопроса

Если кассир спрашивает цену товара, ответ нужен сейчас. Если магазин отправляет отчёт в бухгалтерию, это может занять очередь.

Синхронный запрос хорош, когда пользователю нужен результат прямо сейчас: проверить пароль, показать цену, подтвердить доступ. Он проще для UX и отладки, но связывает availability вызывающего и вызываемого сервиса.

Асинхронность подходит для работы, которую можно выполнить позже: email, indexing, analytics, webhook delivery, report generation, enrichment. Она снижает coupling, но требует статусов, повторов, dead-letter queue и observability.

Событие — это факт, а не команда

«Дверь открыта» — факт. «Открой дверь» — команда. Смешать их можно, но система начнёт спорить о намерениях.

Event описывает то, что уже произошло: OrderPlaced, PaymentCaptured, UserRegistered. Command просит что-то сделать: CapturePayment, SendEmail. В архитектуре полезно не смешивать эти формы.

Если событие используется как скрытая команда, consumer становится зависим от внутреннего намерения producer-а. Это ломает слабую связанность.

§ 02

Асинхронность не должна быть местом, где ошибки исчезают.

Пример: transactional outbox

Секретарь сначала регистрирует письмо в журнале, а потом отправляет. Если почта упала, запись не потеряна.

При создании заказа сервис пишет order и outbox event в одной транзакции. Отдельный worker читает outbox и публикует событие в broker. Если broker временно недоступен, событие остаётся в базе и будет отправлено позже.

Outbox закрывает типичную дыру: данные сохранились, но событие потерялось между commit и publish.

Антипример: очередь как мусорный бак

Корзина для входящих писем не является процессом. Если её никто не разбирает, работа просто спрятана.

Команда отправляет все тяжёлые операции в очередь, но не задаёт retry policy, idempotency, ordering, visibility timeout, DLQ и алерты. В production сообщения зависают, дублируются или обрабатываются часами.

Очередь не делает систему надёжной автоматически. Она переносит сложность из request path в background processing.

Самопроверка
  • Нужен ли результат пользователю прямо сейчас? - Что произойдёт при дубле сообщения? - Где хранится факт, что событие должно быть опубликовано? - Как система показывает backlog и failed jobs?