← Назад к вопросам

Приведи пример задачи оркестрирования, которую решал

2.7 Senior🔥 101 комментариев
#Docker, Kubernetes и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оркестрирование: примеры из опыта

Оркестрирование — координация нескольких асинхронных операций или микросервисов для достижения результата. Вот реальные примеры из практики.

Пример 1: Обработка заказа в e-commerce

Задача: Пользователь нажимает "Купить". Нужно:

  1. Проверить наличие товара на складе
  2. Зарезервировать товар
  3. Списать деньги с карты
  4. Создать заказ
  5. Отправить уведомление
  6. Создать доставку

Проблема: Если что-то упадёт на шаге 4, но шаг 3 прошёл успешно — деньги списаны, но заказа нет. Нужна оркестрация этого процесса.

Решение с Saga паттерном:

@Service
@RequiredArgsConstructor
public class OrderOrchestrator {
    private final InventoryService inventory;
    private final PaymentService payment;
    private final OrderService order;
    private final NotificationService notification;
    private final DeliveryService delivery;
    
    public Order processOrder(OrderRequest request) {
        // Шаг 1: Резервирование
        Reservation reservation = inventory.reserve(request.getProductId());
        
        try {
            // Шаг 2: Платёж
            Transaction transaction = payment.charge(request.getCardId(), 
                                                     request.getAmount());
            try {
                // Шаг 3: Создание заказа
                Order newOrder = order.create(request, reservation, transaction);
                
                try {
                    // Шаг 4: Уведомление (опциональное)
                    notification.sendConfirmation(newOrder);
                } catch (Exception e) {
                    // Уведомление упало, но заказ в порядке
                    log.warn("Notification failed for order " + newOrder.getId(), e);
                }
                
                try {
                    // Шаг 5: Доставка
                    Delivery deliveryInfo = delivery.schedule(newOrder);
                    newOrder.setDelivery(deliveryInfo);
                } catch (Exception e) {
                    // Доставку можно отложить
                    log.warn("Delivery scheduling failed", e);
                }
                
                return newOrder;
                
            } catch (Exception e) {
                // Откатываем платёж если заказ не создан
                payment.refund(transaction);
                throw e;
            }
        } catch (Exception e) {
            // Отменяем резервирование если платёж упал
            inventory.cancel(reservation);
            throw e;
        }
    }
}

Пример 2: Обработка платежа через несколько провайдеров

Задача: У нас есть несколько платёжных систем (Stripe, PayPal, Google Pay). Когда пользователь платит:

  1. Попробовать Stripe
  2. Если упал — попробовать PayPal
  3. Если упал — попробовать Google Pay
  4. Если все упали — вернуть ошибку

Оркестрация:

@Service
@RequiredArgsConstructor
public class PaymentOrchestrator {
    private final StripePaymentService stripe;
    private final PayPalPaymentService paypal;
    private final GooglePayService googlePay;
    
    public Transaction processPayment(PaymentRequest request) {
        List<PaymentProvider> providers = Arrays.asList(
            new PaymentProvider("Stripe", stripe),
            new PaymentProvider("PayPal", paypal),
            new PaymentProvider("GooglePay", googlePay)
        );
        
        Exception lastException = null;
        
        for (PaymentProvider provider : providers) {
            try {
                log.info("Attempting payment with {}", provider.getName());
                Transaction transaction = provider.process(request);
                log.info("Payment successful with {}", provider.getName());
                return transaction;
            } catch (PaymentGatewayException e) {
                log.warn("Payment failed with {}: {}", 
                         provider.getName(), e.getMessage());
                lastException = e;
                // Пробуем следующий
            }
        }
        
        throw new PaymentFailedException(
            "All payment providers failed", lastException);
    }
}

Пример 3: Асинхронная оркестрация с CompletableFuture

Задача: Для страницы профиля пользователя нужна:

  1. Информация о пользователе (из UserService)
  2. История заказов (из OrderService)
  3. Рекомендации (из RecommendationService)
  4. Статистика (из AnalyticsService)

Эти сервисы независимы, можем вызвать параллельно.

Решение:

@Service
@RequiredArgsConstructor
public class ProfileOrchestrator {
    private final UserService userService;
    private final OrderService orderService;
    private final RecommendationService recommendationService;
    private final AnalyticsService analyticsService;
    
    public CompletableFuture<UserProfile> buildProfile(Long userId) {
        // Получаем пользователя (нужен для остального)
        CompletableFuture<User> userFuture = 
            CompletableFuture.supplyAsync(() -> userService.getUser(userId));
        
        // Параллельно вызваны остальные
        CompletableFuture<List<Order>> ordersFuture =
            userFuture.thenCompose(user -> 
                CompletableFuture.supplyAsync(() -> 
                    orderService.getUserOrders(userId)));
        
        CompletableFuture<List<Recommendation>> recommendationsFuture =
            userFuture.thenCompose(user ->
                CompletableFuture.supplyAsync(() ->
                    recommendationService.getForUser(userId)));
        
        CompletableFuture<Statistics> statsFuture =
            userFuture.thenCompose(user ->
                CompletableFuture.supplyAsync(() ->
                    analyticsService.getStats(userId)));
        
        // Комбинируем результаты
        return CompletableFuture.allOf(
                userFuture, ordersFuture, 
                recommendationsFuture, statsFuture)
            .thenApply(v -> new UserProfile(
                userFuture.join(),
                ordersFuture.join(),
                recommendationsFuture.join(),
                statsFuture.join()
            ));
    }
}

Пример 4: Оркестрация с Temporal.io (для сложных workflows)

Задача: Длительный процесс согласования отпуска:

  1. Сотрудник подаёт заявку
  2. Отправляем уведомление руководителю
  3. Ждём 3 дня или ответа
  4. Если одобрено — обновляем график
  5. Отправляем уведомление сотруднику

Решение с Temporal:

// Интерфейс workflow'а
public interface LeaveApprovalWorkflow {
    void approveLeave(LeaveRequest request);
}

// Реализация
public class LeaveApprovalWorkflowImpl implements LeaveApprovalWorkflow {
    private final LeaveActivities activities = 
        Workflow.newActivityStub(LeaveActivities.class,
            ActivityOptions.newBuilder()
                .setScheduleToCloseTimeout(Duration.ofDays(1))
                .build());
    
    @Override
    public void approveLeave(LeaveRequest request) {
        // 1. Сохраняем заявку
        activities.saveRequest(request);
        
        // 2. Отправляем уведомление руководителю
        activities.notifyManager(request);
        
        // 3. Ждём ответа максимум 3 дня
        ApprovalDecision decision = Workflow.await(
            Duration.ofDays(3),
            () -> activities.getDecision(request.getId())
        );
        
        if (decision.isApproved()) {
            // 4. Обновляем график
            activities.updateSchedule(request);
            
            // 5. Уведомляем сотрудника
            activities.notifyEmployee(request, "Approved");
        } else {
            activities.notifyEmployee(request, "Rejected");
        }
    }
}

Пример 5: Оркестрация с Spring Cloud (микросервисы)

Задача: Заказ проходит через несколько микросервисов:

  • Order Service
  • Inventory Service
  • Payment Service
  • Shipping Service

Оркестрация через API Gateway:

@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderGateway {
    private final RestTemplate restTemplate;
    
    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
        try {
            // 1. Зарезервировать товар
            InventoryResponse inv = restTemplate.postForObject(
                "http://inventory-service/reserve",
                request, InventoryResponse.class);
            
            // 2. Списать деньги
            PaymentResponse payment = restTemplate.postForObject(
                "http://payment-service/charge",
                new PaymentRequest(request.getAmount()),
                PaymentResponse.class);
            
            // 3. Создать заказ
            OrderResponse order = restTemplate.postForObject(
                "http://order-service/create",
                new OrderCreateRequest(inv.getId(), payment.getId()),
                OrderResponse.class);
            
            // 4. Запланировать доставку
            ShippingResponse shipping = restTemplate.postForObject(
                "http://shipping-service/schedule",
                new ShippingRequest(order.getId()),
                ShippingResponse.class);
            
            return ResponseEntity.ok(mapToOrder(order, shipping));
            
        } catch (Exception e) {
            // Откатываем при ошибке
            return ResponseEntity.status(500).build();
        }
    }
}

Различия между подходами

ПодходКогда использоватьСложность
Синхронная (try-catch)Простые процессы, < 5 шаговНизкая
CompletableFutureПараллельные операцииСредняя
Saga паттернНужна компенсация при ошибкеВысокая
Temporal.ioДлительные workflow'ыОчень высокая
Event-drivenАсинхронные событияСредняя

Что я обычно выбираю

Для стартапов: Простая синхронная оркестрация в сервисе.

Для масштабируемых систем: CompletableFuture для параллелизма + Saga для компенсации.

Для сложных процессов: Temporal.io или Apache Airflow.

Заключение

Оркестрирование — это координация нескольких асинхронных операций для достижения единого результата. В Java это реализуется:

  • Синхронно через обычные try-catch блоки
  • Асинхронно через CompletableFuture
  • Надёжно через Saga паттерн
  • Масштабируемо через Temporal.io или event-driven архитектуру

Выбор подхода зависит от сложности процесса и требований к надёжности.