> Что такое саги в микросервисах (JavaScript)

Уровень: junior · Роль: backend · Язык: JavaScript · Категория: Технические вопросы

Компании: TrendTech

Стек: Node.js, JavaScript

> Пример ответа

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

Саги в микросервисах - это паттерн для управления распределёнными транзакциями. Вместо ACID используется последовательность локальных транзакций с компенсирующими действиями при сбоях. Каждый сервис выполняет свою операцию и публикует событие, запускающее следующий шаг. Если что-то идёт не так, запускаются компенсирующие транзакции для отката уже выполненных шагов.

Подробное объяснение

В монолитной архитектуре транзакции обычно обрабатываются с помощью ACID - атомарность, согласованность, изоляция, долговечность. В микросервисах каждый сервис имеет свою базу данных, поэтому распределённые транзакции через двухфазный коммит (2PC) становятся сложными и медленными. Саги решают эту проблему, разбивая транзакцию на несколько локальных шагов.

Существует два подхода к реализации саг:

  1. Хореография (choreography) - каждый сервис после выполнения своей операции публикует событие, на которое подписываются другие сервисы. Нет центрального координатора. Пример: сервис заказов создаёт заказ → публикует событие OrderCreated → сервис оплаты обрабатывает оплату → публикует PaymentProcessed → сервис доставки начинает доставку.

  2. Оркестрация (orchestration) - есть центральный оркестратор, который управляет последовательностью шагов и вызывает каждый сервис. Оркестратор хранит состояние саги и при ошибке запускает компенсирующие действия.

Компенсирующие транзакции - это действия, которые отменяют эффект уже выполненного шага. Например, если оплата прошла, а доставка не удалась, нужно вернуть деньги. Компенсация должна быть идемпотентной и надёжной.

На практике

В Node.js саги часто реализуются с помощью message broker (например, RabbitMQ, Kafka) или библиотек вроде sagas-js, brigade или temporal. Для хореографии используют event-driven подход: сервисы общаются через события. Для оркестрации - отдельный микросервис-оркестратор, который вызывает API других сервисов.

Важно учитывать:

  • Саги не гарантируют изоляцию - возможны промежуточные состояния, видимые другим сервисам.
  • Нужна идемпотентность обработчиков событий и компенсирующих действий.
  • События должны быть durable (сохраняться в очередь) и обрабатываться в правильном порядке.
  • Мониторинг и логирование критичны для отладки сбоев в сагах.

Пример кода

Пример простой хореографии саги для заказа:

JAVASCRIPT
// Сервис заказов
class OrderService {
async createOrder(orderData) {
const order = await db.orders.create(orderData);
await eventBus.publish('order.created', { orderId: order.id });
return order;
}
async compensateOrder(orderId) {
await db.orders.update(orderId, { status: 'cancelled' });
await eventBus.publish('order.cancelled', { orderId });
}
}
// Сервис оплаты
class PaymentService {
async handleOrderCreated(event) {
try {
const payment = await processPayment(event.orderId);
await eventBus.publish('payment.processed', { orderId: event.orderId });
} catch (error) {
await eventBus.publish('payment.failed', { orderId: event.orderId });
}
}
async compensatePayment(orderId) {
await refundPayment(orderId);
await eventBus.publish('payment.refunded', { orderId });
}
}
// Сервис доставки
class DeliveryService {
async handlePaymentProcessed(event) {
try {
await scheduleDelivery(event.orderId);
await eventBus.publish('delivery.scheduled', { orderId: event.orderId });
} catch (error) {
await eventBus.publish('delivery.failed', { orderId: event.orderId });
}
}
}
// Компенсация при сбое доставки
eventBus.on('delivery.failed', async (event) => {
await paymentService.compensatePayment(event.orderId);
await orderService.compensateOrder(event.orderId);
});

Как отвечать на собеседовании

Начни с краткого определения саги как паттерна для распределённых транзакций. Объясни проблему, которую решают саги - невозможность ACID в микросервисах. Упомяни два подхода: хореография и оркестрация. Приведи простой пример из e-commerce: заказ → оплата → доставка. Скажи, что в Node.js часто используют message broker и event-driven архитектуру. Не углубляйся в детали реализации, если не спрашивают.

Что проверяет интервьюер

  • Понимание ограничений распределённых систем и почему ACID не работает в микросервисах.
  • Знание базовых паттернов для управления транзакциями.
  • Умение различать хореографию и оркестрацию.
  • Понимание компенсирующих транзакций и идемпотентности.
  • Осознание trade-off: саги не дают изоляции, возможны промежуточные состояния.

Типичные ошибки

  • Путать саги с двухфазным коммитом (2PC) - это разные подходы.
  • Думать, что саги гарантируют ACID - они обеспечивают только eventual consistency.
  • Игнорировать идемпотентность - повторные события могут вызвать дублирование операций.
  • Не предусматривать компенсирующие действия для каждого шага.
  • Считать, что саги подходят для всех случаев - иногда достаточно простой очереди с retry.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью