Урок 2 · ~8 минут

Как устроен Temporal: четыре роли

Одна идея этого урока: в Temporal всего четыре ключевых участника, и у каждого – простая понятная роль.

Театральная аналогия

Проще всего представить Temporal как театральную постановку:

ПонятиеРоль в театреЧто это на самом деле
WorkflowСценарий пьесыКод с логикой процесса: какие шаги, в каком порядке, что делать при ошибке
ActivityОтдельная сценаОдин конкретный шаг, который трогает внешний мир: вызов API, письмо, запись в базу
WorkerАктёрыВаша программа, которая реально исполняет workflow и activities. Работает на вашем сервере
Temporal ServerРежиссёр с журналомДиспетчер: раздаёт задачи, ведёт Event History, следит за таймаутами и повторами

Задачи от «режиссёра» к «актёрам» попадают через Task Queue – очередь задач. Worker постоянно спрашивает у сервера: «есть работа для меня?» – берёт задачу, выполняет и сообщает результат (docs.temporal.io/workers).

Ваше приложение«запусти процесс оплаты №542»
Temporal Serverведёт журнал, кладёт задачи в очередь
Workerберёт задачи, выполняет ваш код

Главное разделение: Workflow против Activity

Это самое важное правило Temporal, и оно того стоит:

Workflow – чистый «сценарий»: только логика и порядок шагов. Activity – всё, что трогает внешний мир: API, базы, файлы, письма.

Почему так? Вспомните урок 1: после сбоя Temporal «проигрывает» сценарий заново по журналу (это называется Replay), чтобы восстановить, где процесс остановился. Для этого сценарий должен при повторном проигрывании давать тот же результат – быть детерминированным. Уже выполненные activities при этом не выполняются повторно: их результаты берутся из журнала (docs.temporal.io).

Поэтому письмо не отправится дважды: при восстановлении Temporal видит в журнале «шаг „отправить письмо" уже выполнен, результат такой-то» – и просто идёт дальше.

Как это выглядит в коде

Просто чтобы вы узнавали такой код, когда его напишет ваш ИИ-агент (TypeScript, упрощённо):

// Workflow – сценарий: порядок шагов, никаких прямых вызовов API
export async function afterPurchase(order) {
  await grantAccess(order);      // activity: открыть доступ
  await sendWelcomeEmail(order); // activity: письмо
  await addToChat(order);        // activity: чат потока
}

Каждая строка с await – это activity. Если на «письме» сбой, Temporal сам повторит только этот шаг, а «доступ» повторно выдавать не будет.

Бонус: процесс, который умеет ждать

Раз состояние хранится в журнале, workflow может спокойно «спать» – минуту, неделю, месяц. Строчка «подождать 7 дней и, если ученик не открыл курс, отправить напоминание» – это буквально одна строка кода. Серверу не нужно «держать» процесс в памяти всё это время.

Проверьте себя

1. Куда по правилам Temporal нужно поместить вызов API GetCourse?

2. Worker упал и перезапустился посреди процесса. Отправится ли уже отправленное письмо второй раз?

3. Где физически выполняется ваш код (workflow и activities)?

💬 Что-то непонятно? Спросите своего ИИ-агента – например: «покажи, как выглядел бы workflow для моего видеоконвейера».