Разделы

Durable Functions

Движок durable-оркестрации координирует длительные stateful-воркфлоу — цепочки шагов, fan-out и ожидание событий или подтверждений. Каждый запуск чекпойнтится в Postgres, поэтому прогоны переживают рестарты — без отдельной очереди или хранилища состояния, которые пришлось бы обслуживать. Про durable-ретраи для развёрнутых функций-контейнеров смотрите также фоновые задачи.

Оркестратор (async-генератор) пошагово вызывает функции-активности. Каждый шаг чекпойнтится в Postgres, поэтому прогресс надёжен: после рестарта оркестратор переигрывает записанную историю и продолжает ровно с того места, где остановился.

Как работает оркестрация

Пишите оркестратор как async-генератор и делайте yield на каждом шаге. Активности выполняют реальную работу (могут быть недетерминированы); оркестратор только координирует и обязан быть детерминированным — используйте ctx.callActivity() для результатов и ctx.currentUtcDateTime для времени, а не Date.now() или Math.random().

ctx.callActivityWithRetry() повторяет нестабильный шаг с экспоненциальной задержкой, а ctx.continueAsNew() перезапускает длинный цикл с чистым состоянием, чтобы история оставалась ограниченной.

Цикл durable-оркестрации: resume-задача реплеит генератор по истории; активности выполняются в том же ходе; ожидание таймера или внешнего события записывает команду и приостанавливает выполнение со статусом WAITING; когда таймер срабатывает или событие приходит, ставится новая resume-задача; когда генератор возвращает значение, оркестрация становится COMPLETED
Один ход за раз: реплей дёшев, потому что записанные команды мемоизированы, а ожидание не тратит компьют — контейнер освобождается, пока инстанс в WAITING.
orchestrator.js
// orchestrator.js — coordinate activities, a durable timer, and an approval gate.
// Register it like any function, then start it via global.durable or the HTTP API.
exports.orchestrator = async function* (ctx) {
  const order = ctx.getInput();

  // Each activity result is checkpointed to Postgres (replayed, not re-run, on resume).
  const charged = yield ctx.callActivity('chargeCard', order);

  // Retry a flaky step with exponential backoff.
  yield ctx.callActivityWithRetry('reserveStock', {
    maxNumberOfAttempts: 3,
    firstRetryIntervalInMilliseconds: 1000,
    backoffCoefficient: 2,
  }, order);

  // Durable timer — the orchestration suspends (no container, no compute) for 24h.
  yield ctx.createTimer(new Date(Date.now() + 24 * 60 * 60 * 1000));

  // Wait for a human approval or webhook — resumes when the event is raised.
  const approval = yield ctx.waitForExternalEvent('Approval', 86400000);

  if (approval && approval.approved) {
    return yield ctx.callActivity('ship', order);
  }
  return yield ctx.callActivity('refund', charged);
};

Durable-таймеры и внешние события

ctx.createTimer() ждёт минуты, часы или дни, а ctx.waitForExternalEvent() приостанавливает оркестрацию до прихода именованного события (подтверждение человека, колбэк вебхука). Во время ожидания оркестрация приостановлена: она не держит контейнер и не расходует вычислительные ресурсы — и возобновляется автоматически, когда срабатывает таймер или приходит событие.

Запуск и управление оркестрациями

Из функции внедрённый клиент global.durable управляет инстансами: startNew(name, id?, input?), getStatus(id), waitForCompletion(id, ms), raiseEvent(id, name, data) и terminate(id, reason). Необязательный ключ идемпотентности у startNew устраняет дубли запусков.

HTTP API

Оркестрациями можно управлять и по HTTP: POST /durable/orchestrations/{name}/start возвращает 202 с идентификатором инстанса и URI для статуса, отправки события и завершения; прогресс опрашивайте через GET /durable/orchestrations/{id}/status.