> Зачем нужен отдельный сервис на 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.
Пример кода
GOpackage orchestratortype Workflow struct {ID stringState stringData map[string]any}type Orchestrator struct {store Storequeue Queuelogger *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).
- Понимаете ли вы проблемы распределённых систем: потеря сообщений, идемпотентность, восстановление состояния.
- Видите ли вы границы ответственности между сервисами.
Типичные ошибки
- Говорить "чтобы было быстрее" - скорость не главная причина, важнее изоляция и масштабируемость.
- Не упоминать про восстановление состояния после рестарта - это ключевая проблема оркестратора.
- Смешивать оркестратор с воркерами: воркеры выполняют шаги, оркестратор только управляет порядком.
- Забывать про идемпотентность: повторная обработка события не должна ломать состояние.
- Предлагать хранить состояние в памяти без персистентности - это нежизнеспособно для продакшена.
> Похожие задачи по Go
Для какого механизма Go нужны методы с ресиверами по указателю
Почему нельзя заменить канал в Go обычным слайсом сообщений?
Как устроен оркестратор, управляющий задачами для платежей
Что такое MVCC в PostgreSQL
> Похожие задачи по backend
Для какого механизма Go нужны методы с ресиверами по указателю
Почему нельзя заменить канал в Go обычным слайсом сообщений?
Как устроен оркестратор, управляющий задачами для платежей
Что такое MVCC в PostgreSQL
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью