Питання 2 · Розділ 17

У чому різниця між хореографією та оркестрацією в Saga

// Чим оркестратор відрізняється від звичайного методу: // 1. Персистить стан (переживає рестарти) // 2. Обробляє асинхронні події // 3. Має built-in retry та compensation

Мовні версії: English Russian Ukrainian

🟢 Junior Level

Хореографія і оркестрація — два способи реалізації патерну Saga.

Хореографія — немає центрального керуючого. Кожен сервіс слухає події інших сервісів і реагує.

Оркестрація — є центральний оркестратор, який каже кожному сервісу що робити.

// Чим оркестратор відрізняється від звичайного методу: // 1. Персистить стан (переживає рестарти) // 2. Обробляє асинхронні події // 3. Має built-in retry та compensation

Хореографія:
Order Service → "OrderCreated" → Payment Service → "PaymentDone" → Shipping Service

Оркестрація:
     Orchestrator
    /     |      \
Order  Payment  Shipping
  ↓       ↓        ↓
"створи" "оплати" "відправ"

🟡 Middle Level

Хореографія — Event-driven

// Order Service
@EventListener
public void on(OrderCreatedEvent event) {
    paymentService.reserve(event.orderId());
    eventPublisher.publish(new PaymentReservedEvent(event.orderId()));
}

// Payment Service
@EventListener
public void on(PaymentReservedEvent event) {
    shippingService.ship(event.orderId());
    eventPublisher.publish(new ShippingCompletedEvent(event.orderId()));
}

// Компенсація
@EventListener
public void on(PaymentFailedEvent event) {
    orderService.cancel(event.orderId());
    eventPublisher.publish(new OrderCancelledEvent(event.orderId()));
}

Оркестрація — Central coordinator

@Component
public class OrderOrchestrator {

    public void processOrder(Order order) {
        try {
            orderService.create(order);
            paymentService.charge(order);
            inventoryService.reserve(order);
            shippingService.ship(order);
        } catch (PaymentException e) {
            orderService.cancel(order);
            // throw e — виключення піднімається до HTTP-контролера,
            // який повертає клієнту 500 з описом помилки компенсації.
            throw e;
        } catch (InventoryException e) {
            paymentService.refund(order);
            orderService.cancel(order);
            // throw e — виключення піднімається до HTTP-контролера,
            // який повертає клієнту 500 з описом помилки компенсації.
            throw e;
        }
    }
}

Порівняння

Хореографія Оркестрація
Без центрального контролю Центральний оркестратор
Event-driven Command-driven
Складно відстежити потік Легко зрозуміти потік
Циклічні залежності Немає циклічних залежностей
При 2-3 сервісах потік подій ще можна тримати в голові. При 5+ сервісах зв’язки ростуть квадратично, і без оркестратора неможливо зрозуміти, хто кого викликає.

Event-driven = сервіси реагують на події (хтось опублікував факт). Command-driven = оркестратор явно каже кожному сервісу «зроби X».

Типові помилки

  1. Циклічні залежності в хореографії:
    Service A → подія → Service B → подія → Service A → нескінченний цикл!
    

🔴 Senior Level

Архітектурні Trade-offs

Хореографія:

Плюси:
- Немає single point of failure
- Слабка пов'язаність сервісів
- Природний event-driven стиль

Мінуси:
- Складно дебажити (потік неочевидний)
- Ризик циклічних залежностей
- Важко додати новий крок
- Немає єдиного місця для моніторингу

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

Плюси:
- Чіткий потік виконання
- Легко додати крок
- Централізований моніторинг
- Немає циклічних залежностей

Мінуси:
- Оркестратор — bottleneck
- Оркестратор — single point of failure
- Оркестратор знає занадто багато про інші сервіси

Production Experience

Коли обрати хореографію:

- 2-3 сервіси
- Проста логіка
- Вже є event-driven інфраструктура
- Потрібна максимальна відмовостійкість

Коли обрати оркестрацію:

- 5+ сервісів
- Складна логіка з умовами
- Потрібен моніторинг і tracing
- Команди різні для кожного сервісу

Real-world orchestrator (Axon Framework):

@Saga
public class OrderSaga {
    @Autowired
    private transient CommandGateway commandGateway;

    @StartSaga
    @SagaEventHandler(associationProperty = "orderId")
    public void handle(OrderCreatedEvent event) {
        commandGateway.send(new ReserveInventoryCommand(event.getOrderId()));
    }

    @SagaEventHandler(associationProperty = "orderId")
    public void handle(InventoryReservedEvent event) {
        commandGateway.send(new ProcessPaymentCommand(event.getOrderId()));
    }

    @SagaEventHandler(associationProperty = "orderId")
    public void handle(PaymentCompletedEvent event) {
        commandGateway.send(new CompleteOrderCommand(event.getOrderId()));
        end();
    }

    @SagaEventHandler(associationProperty = "orderId")
    public void handle(PaymentFailedEvent event) {
        commandGateway.send(new CancelOrderCommand(event.getOrderId()));
        end();
    }
}

Best Practices

✅ Хореографія для простих Saga (2-3 кроки)
✅ Оркестрація для складних Saga (5+ кроків)
✅ Моніторьте Saga в обох підходах
✅ Реалізуйте idempotency

❌ Не змішуйте підходи в одній Saga
❌ Не створюйте циклічні залежності в хореографії
❌ Не робіть оркестратор занадто "розумним"

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Хореографія — event-driven, без центрального контролю, сервіси реагують на події
  • Оркестрація — command-driven, центральний координатор керує потоком
  • Хореографія: немає SPOF, але складно дебажити, ризик циклічних залежностей
  • Оркестрація: чіткий потік, легко моніторити, але оркестратор — bottleneck
  • Хореографія для простих Saga (2-3 кроки), оркестрація для складних (5+)
  • У хореографії кожен сервіс знає тільки про сусідів, в оркестрації — оркестратор знає про всіх
  • Обидва підходи вимагають idempotency і компенсацій

Часті уточнюючі питання:

  • Як уникнути циклічних залежностей у хореографії? Проектувати спрямований граф подій, використовувати оркестрацію при складній логіці.
  • Що якщо оркестратор впав? Персистить стан — після перезапуску продовжує з місця збою.
  • Чи можна комбінувати підходи? Не в одній Saga, але різні Saga в системі можуть використовувати різні підходи.
  • Як тестувати оркестратор? Unit-тести логіки + інтеграційні тести з мокнутими сервісами.

Червоні прапорці (НЕ говорити):

  • “Хореографія простіша для 10 сервісів” — ні, потік стане нечитаемим
  • “Оркестратор не може впасти” — може, потрібна персистентність стану
  • “У хореографії немає coupling” — є, через події
  • “Оркестратор = антипатерн, порушує loose coupling” — це trade-off, а не абсолют

Пов’язані теми:

  • [[1. Що таке патерн Saga і коли його використовувати]]
  • [[3. Як реалізувати розподілені транзакції в мікросервісах]]
  • [[4. Що таке компенсувальні транзакції]]
  • [[15. Як організувати комунікацію між мікросервісами]]
  • [[26. Які інструменти використовуються для оркестрації мікросервісів]]