← Назад к вопросам
Как оркестрировался бизнес-флоу в микросервисах на последней работе
3.0 Senior🔥 181 комментариев
#REST API и микросервисы#SOLID и паттерны проектирования#Брокеры сообщений
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Оркестрация бизнес-флоу в микросервисах
На последней работе я использовал несколько подходов для оркестрации сложных бизнес-процессов между микросервисами. Расскажу о наиболее значимом проекте.
Контекст: система обработки заказов
Мы разработали систему электронной коммерции с микросервисной архитектурой:
- Order Service — управление заказами
- Payment Service — обработка платежей
- Inventory Service — управление складом
- Notification Service — отправка уведомлений
- Shipping Service — доставка
Подход 1: Оркестрация через Saga Pattern
Использовал Saga pattern для управления распределёнными транзакциями.
Choreography-based Saga
// Order Service
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
@Transactional
public Order createOrder(CreateOrderRequest request) {
Order order = new Order(request);
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
// Отправляем событие
rabbitTemplate.convertAndSend(
"order.exchange",
"order.created",
new OrderCreatedEvent(order.getId(), order.getTotalAmount())
);
return order;
}
}
// Payment Service слушает события
@Service
public class PaymentService {
@RabbitListener(queues = "payment.queue")
@Transactional
public void handleOrderCreated(OrderCreatedEvent event) {
try {
Payment payment = processPayment(event.getOrderId(), event.getAmount());
rabbitTemplate.convertAndSend(
"order.exchange",
"payment.completed",
new PaymentCompletedEvent(event.getOrderId(), payment.getId())
);
} catch (PaymentException e) {
rabbitTemplate.convertAndSend(
"order.exchange",
"payment.failed",
new PaymentFailedEvent(event.getOrderId(), e.getMessage())
);
}
}
}
// Inventory Service реагирует на успешный платёж
@Service
public class InventoryService {
@RabbitListener(queues = "inventory.queue")
@Transactional
public void handlePaymentCompleted(PaymentCompletedEvent event) {
try {
reserveItems(event.getOrderId());
rabbitTemplate.convertAndSend(
"order.exchange",
"inventory.reserved",
new InventoryReservedEvent(event.getOrderId())
);
} catch (InsufficientStockException e) {
// Компенсирующая транзакция: откатить платёж
rabbitTemplate.convertAndSend(
"order.exchange",
"order.failed",
new OrderFailedEvent(event.getOrderId())
);
}
}
}
Подход 2: Оркестрация через Orchestrator (Service)
Создал отдельный Order Orchestrator для управления флоу.
@Service
public class OrderOrchestrator {
@Autowired
private OrderServiceClient orderClient;
@Autowired
private PaymentServiceClient paymentClient;
@Autowired
private InventoryServiceClient inventoryClient;
@Autowired
private ShippingServiceClient shippingClient;
@Transactional
public Order executeOrderFlow(CreateOrderRequest request) {
// Шаг 1: Создаём заказ
Order order = orderClient.createOrder(request);
try {
// Шаг 2: Обрабатываем платёж
Payment payment = paymentClient.processPayment(
order.getId(),
order.getTotalAmount()
);
// Шаг 3: Резервируем товары
InventoryReservation reservation = inventoryClient.reserve(
order.getId(),
order.getItems()
);
// Шаг 4: Создаём отправку
Shipment shipment = shippingClient.createShipment(
order.getId(),
order.getDeliveryAddress()
);
// Шаг 5: Обновляем статус
order.setStatus(OrderStatus.CONFIRMED);
order.setPaymentId(payment.getId());
order.setReservationId(reservation.getId());
order.setShipmentId(shipment.getId());
return orderClient.updateOrder(order);
} catch (PaymentException e) {
handlePaymentFailure(order);
throw e;
} catch (InventoryException e) {
handleInventoryFailure(order);
throw e;
}
}
private void handlePaymentFailure(Order order) {
order.setStatus(OrderStatus.FAILED);
orderClient.updateOrder(order);
}
private void handleInventoryFailure(Order order) {
// Компенсирующая транзакция
paymentClient.refund(order.getId());
order.setStatus(OrderStatus.CANCELLED);
orderClient.updateOrder(order);
}
}
Подход 3: Использование Temporal Workflows
Для сложных, долгоживущих процессов использовал Temporal (на основе Cadence).
public interface OrderWorkflow {
OrderResult processOrder(OrderRequest request);
}
@WorkflowImpl
public class OrderWorkflowImpl implements OrderWorkflow {
private final OrderActivities activities = Workflow.newActivityStub(
OrderActivities.class,
ActivityOptions.newBuilder()
.setStartToCloseTimeout(Duration.ofMinutes(10))
.setRetryPolicy(defaultRetryPolicy())
.build()
);
@Override
public OrderResult processOrder(OrderRequest request) {
try {
// Шаг 1: Создать заказ
OrderInfo order = activities.createOrder(request);
// Шаг 2: Обработать платёж (с retry)
PaymentResult payment = activities.processPayment(
order.getId(),
order.getAmount()
);
// Шаг 3: Зарезервировать товары
InventoryResult inventory = activities.reserveInventory(
order.getId(),
request.getItems()
);
// Шаг 4: Создать отправку
ShippingResult shipping = activities.createShipment(
order.getId(),
request.getDeliveryAddress()
);
return new OrderResult(OrderStatus.SUCCESS, order.getId());
} catch (ApplicationFailure e) {
// Компенсирующие транзакции
activities.compensatePayment(request.getPaymentId());
activities.compensateInventory(request.getOrderId());
return new OrderResult(OrderStatus.FAILED, null);
}
}
}
@ActivityImpl
public class OrderActivitiesImpl implements OrderActivities {
@Override
public PaymentResult processPayment(String orderId, BigDecimal amount) {
// Может быть переиспользована при перезапуске Workflow
return paymentService.process(orderId, amount);
}
}
Сравнение подходов
| Подход | Сложность | Гибкость | Отказоустойчивость |
|---|---|---|---|
| Choreography (Events) | Средняя | Высокая | Требует компенсации |
| Orchestrator Service | Низкая | Средняя | Хорошая |
| Temporal Workflows | Высокая | Высокая | Отличная (встроена) |
Критерии выбора
- Choreography — для простых, независимых процессов с несколькими сервисами
- Orchestrator — для средних по сложности флоу (3-4 сервиса)
- Temporal — для долгоживущих, сложных процессов с высокими требованиями к надёжности
Best Practices, которые мы применили
- Idempotency keys — для предотвращения повторной обработки
- Circuit Breaker — для защиты от каскадных отказов
- Dead Letter Queues — для обработки ошибок
- Event Sourcing — для полного аудита операций
- Monitoring & Tracing — Prometheus + Jaeger для видимости
- Compensation Logic — явная компенсация для откатов
Этот опыт показал, что выбор оркестрации зависит от специфики бизнес-процесса и требований к отказоустойчивости.