make lintmake test-ordermake start
make stopНужно реализовать 3 микросервиса, которые взаимодействуют между собой через Kafka и моделируют полный цикл заказа — от создания до доставки.
Главная идея:
- Order Service создаёт заказ и публикует событие в Kafka.
- Payment Service принимает заказы, моделирует оплату (успешно/ошибка), публикует событие в Kafka.
- Shipping Service принимает события об успешных оплатах и создает отгрузки.
- Order Service слушает все обратные события и обновляет статусы заказа в БД.
Все взаимодействие между сервисами — только через Kafka. REST используется только для создания заказа и просмотра статуса.
+---------------------+
| Order API |
| (создание, статус) |
+---------+-----------+
|
kafka ↓ | ↑ kafka
+---------------------+ +---------+-----------+ +---------------------+
| Payment Service | ← | Kafka Topics | → | Shipping Service |
| (обработка платежей)| | orders, payments, | | (создание отгрузки) |
| | | shipments, cancels | | |
+---------------------+ +---------------------+ +---------------------+
- Order → публикует событие "OrderCreated" в `orders`
- Payment → слушает `orders`, публикует `payments` или `cancels`
- Shipping → слушает `payments`, публикует `shipments`
- Order → слушает все топики и обновляет статус заказа
Функциональность:
- REST API:
POST /orders— создать заказ (в БД, статусCREATED)GET /orders/{id}— получить текущий статус заказа
- После создания — публикует событие
OrderCreatedв Kafka (orders). - Слушает Kafka-топики:
payments— если пришлоPAID, обновить заказ в БД наPAID.shipments— если пришлоSHIPPED, обновить заказ в БД наSHIPPED.cancels— если пришлоCANCELLED, обновить заказ в БД наCANCELLED.
- Использует Inbox Pattern:
- Все входящие Kafka-сообщения сначала сохраняются в таблицу
inboxсmessage_id, чтобы обеспечить идемпотентность (одно сообщение обрабатывается только один раз).
- Все входящие Kafka-сообщения сначала сохраняются в таблицу
Функциональность:
- Подписывается на Kafka-топик
orders. - При получении нового заказа:
- Сохраняет событие в
inbox(идемпотентность). - Проверяет условие:
- Если
orderId % 2 == 0→ симулирует ошибку оплаты, публикуетPaymentFailedв топикcancels:{ "orderId": 2, "status": "CANCELLED", "reason": "INSUFFICIENT_FUNDS" } - Если
orderId % 2 == 1→ симулирует успешную оплату, публикуетPaymentSuccessв топикpayments:{ "orderId": 1, "status": "PAID", "amount": 150.0 }
- Если
- Сохраняет событие в
- (Опционально) Имеет REST
GET /paymentsдля просмотра истории платежей.
Функциональность:
- Подписывается на Kafka-топик
payments. - При получении
PaymentSuccess:- Сохраняет событие в
inbox(идемпотентность). - Создает запись об отгрузке (в БД, статус
SHIPPED, генерируетtrackingNumber). - Публикует событие
OrderShippedв топикshipments:{ "orderId": 1, "status": "SHIPPED", "trackingNumber": "SHIP-ABC123" }
- Сохраняет событие в
| Топик | Отправитель | Получатель | Описание |
|---|---|---|---|
orders |
Order Service | Payment Service | События создания заказов |
payments |
Payment Service | Order & Shipping Service | Успешные оплаты |
shipments |
Shipping Service | Order Service | События об отгрузках |
cancels |
Payment Service | Order Service | Отменённые заказы |
Каждый сервис обязан:
- Иметь таблицу
inbox(например:id,message_id,payload,processed_at). - При получении Kafka-сообщения:
- Проверить, есть ли
message_idвinbox. - Если нет — сохранить и обработать.
- Если есть — пропустить (сообщение уже обработано).
- Проверить, есть ли
Каждый сервис должен иметь собственную БД в продакшене (для простоты можно использовать одну базу в докере, чтобы экономить ресурсы, только создавайте таблицы с префиксом сервиса):
- Order Service — таблицы
orders,inbox - Payment Service — таблицы
payments,inbox - Shipping Service — таблицы
shipments,inbox
POST /orders→ создаёт заказ#1- Order Service сохраняет заказ → публикует
OrderCreated.
- Order Service сохраняет заказ → публикует
- Payment Service получает
OrderCreated:- Если
orderId % 2 == 1: публикуетPaymentSuccess. - Если
orderId % 2 == 0: публикуетPaymentFailed.
- Если
- Order Service слушает события:
- Обновляет статус
PAIDилиCANCELLED.
- Обновляет статус
- Shipping Service слушает
payments:- Создаёт отгрузку → публикует
OrderShipped.
- Создаёт отгрузку → публикует
- Order Service слушает
shipments:- Обновляет статус заказа на
SHIPPED.
- Обновляет статус заказа на
Пример жизненного цикла:
Order #1 → CREATED → PAID → SHIPPED
Order #2 → CREATED → CANCELLED