Заказ оформлен. Склад должен начать комплектацию, клиент — получить уведомление, аналитика — учесть покупку. На первый взгляд это одна цепочка. Но нужно ли системе заказов самой знать адрес каждого участника и дожидаться его ответа?
Event-Driven Architecture предлагает другой принцип: источник сообщает о случившемся факте, а остальные системы реагируют на него по своим правилам. Это уменьшает прямые зависимости. Правда, вместе с зависимостями исчезает и удобная иллюзия, что один вызов контролирует весь процесс.

Событие — не приказ соседней команде
Разница кажется словесной, пока не приходится отвечать за систему. Команда «отправь клиенту письмо» адресована конкретному исполнителю. Событие «заказ подтверждён» сообщает о факте: заказ действительно перешёл в определённое состояние.
После такого события уведомления могут отправить письмо, склад — создать задачу на сборку, а аналитика — обновить показатели. Система заказов при этом не обязана знать обо всех будущих подписчиках.
Это полезно, когда к продукту подключаются новые процессы. Например, программа лояльности может начать реагировать на покупку без доработки основной логики оформления заказа. Но если участник обязан гарантированно завершить часть критического сценария прежде, чем заказ считается успешным, простого события может быть недостаточно. Тогда потребуются явная координация, ожидание подтверждения или Saga.
Независимость систем не означает независимость результата
Удобно, когда сервис уведомлений временно недоступен, а оформление заказа продолжает работать. Можно положить событие в очередь и доставить позже. Клиент получит письмо с задержкой, но сам заказ не пропадёт.
С оплатой сложнее. Если бизнес считает заказ оплаченным лишь после подтверждения платежа, не стоит отвечать покупателю «всё готово», полагаясь на необработанное событие. Границы бизнес-обещаний должны соответствовать реальному состоянию.
Поэтому я бы сначала разделил реакции на две группы: те, которые могут выполниться позже, и те, без которых основная операция не имеет смысла. Для второй группы потребуется более строгая модель координации, чем «кто-нибудь когда-нибудь обработает».
Сообщение может прийти дважды. Или не тогда, когда его ждут
Распределённый обмен не даёт универсальной гарантии «ровно один раз и точно по порядку». В конкретных брокерах существуют режимы доставки и ограничения порядка, но архитектуру всё равно следует проектировать с учётом повторов, задержек и возможного рассогласования.
Если обработчик дважды получает событие об оплате, он не должен дважды начислить бонус или дважды отправить физическую посылку. Нужны идентификаторы событий, идемпотентная обработка и понятное правило повторных попыток.
Отдельная проблема — разрыв между записью в базу и публикацией сообщения. Если транзакция сохранилась, а приложение упало перед публикацией, остальные системы могут никогда не узнать об изменении. Один из способов закрыть разрыв — Transactional Outbox. Но и после него подписчики должны уметь обрабатывать дубли.
Как узнать, что бизнес-процесс на самом деле закончился
При прямом вызове ошибку часто видно сразу. В событийной цепочке заказ уже записан, сообщения лежат в очереди, а последняя обработка может отставать. Всё формально «работает», кроме нужного клиенту результата.
Нужны корреляционные идентификаторы, мониторинг задержек и ошибок доставки, возможность повторной обработки и отдельное наблюдение за состоянием процесса. Наличие брокера само по себе не отвечает на вопрос, какой заказ завис и почему.
Есть и организационная сторона. Кто поддерживает контракт события? Кто предупредит подписчиков об изменении формата? Кто отвечает за инцидент, если производитель публикует корректный факт, но склад его не обработал? Между командами должна существовать договорённость, а не надежда на инфраструктуру.
Где события не стоят своей цены
Если небольшой сервис вызывает другую функцию внутри одного приложения, очередь между ними вряд ли создаст бизнес-ценность. Она добавит хранение сообщений, повторные попытки, диагностику и задержки там, где раньше был понятный вызов.
Я бы выбирал событийную модель там, где несколько самостоятельных потребителей действительно могут реагировать в разное время и развитие одного не должно блокировать другого. Но сначала попросил бы показать, как система ведёт себя при задержке, повторе и отсутствии сообщения — не на красивой диаграмме, а в рабочем сценарии заказа.
Событийная архитектура хороша, когда мы можем отпустить исполнителей, не потеряв ответственность за результат. Просто убрать прямые вызовы недостаточно.
Технические ограничения дубликатов и порядка подробно разбираются в материале о Transactional Outbox и документации брокера, выбранного в проекте.