Как создавать заказы и надёжно отправлять счета

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

Короткий ответ

Что ответить на собеседовании

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

Подробный разбор

Ответ с пояснениями

Условие

Спроектируйте сервис магазина: запрос создаёт заказ, фиксирует цены товаров и инициирует отправку клиенту счёта на оплату по email. Почтовый сервис иногда недоступен, а клиент может повторить запрос. Как избежать потери заказа и повторного создания?

Ответ

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

Последовательность:

  1. Проверить входные данные и получить доверенные цены на сервере.
  2. В транзакции создать заказ со снимком позиций, суммы и валюты; сохранить outbox-событие с уникальным ID.
  3. Зафиксировать транзакцию и вернуть ID заказа. Не держать её открытой во время обращения к почте.
  4. Обработчик формирует счёт из сохранённых данных, отправляет письмо и отмечает событие обработанным.

При повторном запросе с тем же ключом возвращается прежний результат; другой payload с тем же ключом — конфликт. У отправки нужны повторы с задержкой и наблюдение за окончательными ошибками. Сбой после принятия письма провайдером, но до записи статуса может дать дубль: используйте идемпотентность провайдера, если она доступна. Одного флага sent недостаточно для гарантии ровно одной доставки.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее