Одна идея этого урока: в Temporal всего четыре ключевых участника, и у каждого – простая понятная роль.
Проще всего представить Temporal как театральную постановку:
| Понятие | Роль в театре | Что это на самом деле |
|---|---|---|
| Workflow | Сценарий пьесы | Код с логикой процесса: какие шаги, в каком порядке, что делать при ошибке |
| Activity | Отдельная сцена | Один конкретный шаг, который трогает внешний мир: вызов API, письмо, запись в базу |
| Worker | Актёры | Ваша программа, которая реально исполняет workflow и activities. Работает на вашем сервере |
| Temporal Server | Режиссёр с журналом | Диспетчер: раздаёт задачи, ведёт Event History, следит за таймаутами и повторами |
Задачи от «режиссёра» к «актёрам» попадают через Task Queue – очередь задач. Worker постоянно спрашивает у сервера: «есть работа для меня?» – берёт задачу, выполняет и сообщает результат (docs.temporal.io/workers).
Это самое важное правило 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)?