> Зачем нужен отдельный сервис на Go для оркестратора (Go)

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

Компании: InDrive

Стек: Go

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

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

Отдельный сервис на Go для оркестратора нужен для изоляции критической логики управления workflow от остальной системы. Это даёт независимое масштабирование, отдельный деплой и возможность перезапуска без влияния на API или воркеры. Go здесь оправдан из-за лёгкой конкурентности, быстрого старта и предсказуемого потребления памяти - критично для долгоживущих процессов, которые держат состояние и таймеры.

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

Оркестратор - это сервис, который управляет состоянием распределённых процессов: запускает шаги, обрабатывает retry, таймауты, компенсации. Если встроить его в основной API, вы получите связанность: пики нагрузки на API будут блокировать выполнение workflow, а рестарт API потеряет незавершённые процессы.

Отдельный сервис решает несколько задач:

  • Изоляция сбоев - падение оркестратора не роняет API, и наоборот. Можно перезапускать оркестратор независимо, восстанавливая состояние из storage.
  • Масштабирование по разным осям - API масштабируется по RPS, оркестратор - по количеству активных workflow. Это разные метрики, и они редко совпадают.
  • Отдельный жизненный цикл - вы можете выкатывать новую версию оркестратора без затрагивания пользовательского трафика, и наоборот.
  • Специализированное хранилище - оркестратору нужен свой storage (например, Postgres с таблицей состояний или Redis для таймеров), который не стоит смешивать с данными API.
  • Конкурентная модель - Go с горутинами и каналами хорошо ложится на модель "один workflow = одна горутина". Это упрощает код по сравнению с event-driven подходом на Python или Node.js.

На практике оркестратор часто работает как state machine: получает события, обновляет состояние, отправляет команды воркерам. Отдельный сервис позволяет держать эту логику чистой, без HTTP-хендлеров и бизнес-правил предметной области.

На практике

В реальных проектах оркестратор обычно:

  • слушает очередь (Kafka, NATS) или HTTP-эндпоинты для приёма событий;
  • хранит состояние в Postgres или Redis с TTL;
  • использует outbox pattern для надёжной отправки команд;
  • имеет свой healthcheck и метрики (количество активных workflow, время выполнения, число retry);
  • деплоится отдельным deployment в k8s с собственным HPA по CPU или длине очереди.

Типичный пример - заказ в интернет-магазине: оркестратор координирует резервирование товара, оплату, доставку. Если оплата падает, оркестратор делает retry или запускает компенсацию - и это не должно блокировать другие запросы к API.

Пример кода

GO
package orchestrator
type Workflow struct {
ID string
State string
Data map[string]any
}
type Orchestrator struct {
store Store
queue Queue
logger *slog.Logger
}
func (o *Orchestrator) Run(ctx context.Context, wf *Workflow) error {
for {
switch wf.State {
case "reserve":
err := o.queue.Send("reserve", wf.Data)
if err != nil {
return o.retry(ctx, wf, err)
}
wf.State = "wait_reserve"
case "wait_reserve":
// ждём событие из очереди, обновляем состояние
event, err := o.queue.Receive(ctx, wf.ID)
if err != nil {
return err
}
if event.Type == "reserved" {
wf.State = "payment"
} else {
wf.State = "failed"
}
case "payment":
// аналогично
case "failed":
o.compensate(wf)
return nil
}
o.store.Save(ctx, wf)
}
}

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

Начните с главной причины - изоляция и независимое масштабирование. Затем добавьте про конкурентную модель Go и про то, что оркестратор - это отдельный класс задач с собственными требованиями к хранению и восстановлению. Упомяните, что встроить оркестратор в API можно, но это создаст проблемы с рестартами и нагрузкой. Если спросят про альтернативы - скажите, что можно использовать готовые Temporal или Cadence, но свой сервис оправдан, когда нужен полный контроль над логикой и минимум зависимостей.

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

  • Понимаете ли вы разницу между синхронным API и асинхронным workflow.
  • Умеете ли обосновывать архитектурные решения trade-off'ами, а не "так принято".
  • Знаете ли вы, как Go помогает в конкурентных сценариях (горутины, каналы, context).
  • Понимаете ли вы проблемы распределённых систем: потеря сообщений, идемпотентность, восстановление состояния.
  • Видите ли вы границы ответственности между сервисами.

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

  • Говорить "чтобы было быстрее" - скорость не главная причина, важнее изоляция и масштабируемость.
  • Не упоминать про восстановление состояния после рестарта - это ключевая проблема оркестратора.
  • Смешивать оркестратор с воркерами: воркеры выполняют шаги, оркестратор только управляет порядком.
  • Забывать про идемпотентность: повторная обработка события не должна ломать состояние.
  • Предлагать хранить состояние в памяти без персистентности - это нежизнеспособно для продакшена.

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

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