← Назад к курсу

Пособие по Temporal: Фреймворк для надежных долгоживущих процессов

Что такое Temporal?

Temporal — это распределенный, масштабируемый фреймворк с открытым исходным кодом, предназначенный для оркестрации бизнес-логики и микросервисов. Он гарантирует надежное, устойчивое к сбоям выполнение долгоживущих рабочих процессов (workflow), написанных на обычном коде.

Философия и ключевое отличие

Главная инновация Temporal — Durable Execution (устойчивое выполнение). Это парадигма, при которой состояние приложения (стеки вызовов, локальные переменные) постоянно сохраняется, позволяя процессу пережить сбои инфраструктуры, развертывания нового кода и даже просто перезапуск сервера без потери прогресса.

Сравнение с Airflow: Если Airflow планирует и координирует выполнение отдельных задач (как дирижер), то Temporal запускает и сохраняет состояние всего рабочего процесса целиком, как единую долгоживущую программу.

Ключевые концепции и архитектура

1. Основные компоненты:

  • Temporal Server (Кластер): Управляет очередями, состоянием workflow и истории выполнения. Состоит из сервисов: Frontend, History, Matching, Worker.
  • Worker: Ваше приложение, которое регистрирует и выполняет код workflow и активности. Отделен от кластера, что обеспечивает гибкость развертывания.
  • Клиент SDK: Для взаимодействия с кластером (запуск workflow, отправка запросов).

2. Программная модель (на примере Go SDK):

// Определение Workflow (оркестратор логики)
func MyBusinessWorkflow(ctx workflow.Context, param Input) (Output, error) {
    // 1. Вызов Activity (единица бизнес-логики)
    result1, err := workflow.ExecuteActivity(ctx, ActivityA, param).Get(ctx)
    if err != nil { /* Обработка ошибки */ }

    // 2. Таймер (может длиться дни или месяцы)
    workflow.Sleep(ctx, 24*time.Hour)

    // 3. Сигнал (внешнее событие) - например, ожидание подтверждения от человека
    var signalData string
    workflow.GetSignalChannel(ctx, "approval-signal").Receive(ctx, &signalData)

    // 4. Запрос внешнего API через Activity
    result2, err := workflow.ExecuteActivity(ctx, ActivityB, result1).Get(ctx)
    return Output{Result: result2}, nil
}

// Определение Activity (реализация бизнес-действия)
func ActivityA(ctx context.Context, input Input) (Result, error) {
    // Здесь происходит "работа": вызов API, запись в БД и т.д.
    return Result{Value: "Done"}, nil
}

3. История выполнения (Event History): Ключевая структура данных в Temporal. Это неизменяемая, последовательная запись всех событий в workflow (Activity выполнена, таймер сработал, получен сигнал). Именно эта история позволяет полностью восстановить состояние workflow с любого места после сбоя.

Практические примеры

Пример 1: Обработка заказа в e-commerce

Workflow "ProcessOrder":
1. Активити: Проверить наличие товара и заблокировать.
2. Активити: Списать средства с карты (с автоматическими retry при временных ошибках банка).
3. Таймер: Ждать 30 минут на случай, если пользователь отменит заказ.
4. Сигнал: Если отмена получена — запустить Activity возврата денег.
5. Активити: Создать задание на сборку в логистической системе.
6. Активити: Отправить клиенту трек-номер.
(Workflow может "заснуть" на дни, ожидая доставки, и проснуться для обработки уведомления).

Пример 2: Онбординг пользователя (Multi-step Saga)

Workflow "UserOnboarding":
- Параллельно: Создать учетную запись в сервисе A и сервисе B.
- Если один шаг упал — компенсирующие транзакции (Compensation): откатить создание в другом сервисе.
- Отправить приветственное письмо.
- Запланировать отложенную Activity: отправить напоминание через 3 дня, если пользователь не завершил профиль.

Установка и развертывание

Локальная разработка (с Docker Compose):

git clone https://github.com/temporalio/docker-compose.git
cd docker-compose
docker-compose up

После этого Temporal UI будет доступен на http://localhost:8080.

Продакшен-развертывание: Кластер Temporal можно развернуть на Kubernetes (используя Helm-чарты), в облачных managed-сервисах (Temporal Cloud) или на собственных VM.

Продвинутые возможности и паттерны

  1. Работа с очередями (Queues): Каждый Workflow и Activity Task помещается в свою очередь, что обеспечивает масштабируемость и приоритизацию.
  2. Паттерн "Saga": Temporal — идеальный инструмент для реализации долгоживущих саг в микросервисной архитектуре, где важна согласованность данных.
  3. Паттерн "Работа с человеком в цикле" (Human-in-the-loop): Workflow может приостановиться, ожидая сигнала (например, одобрения менеджера), и продолжить автоматически после его получения.
  4. Паттерн "Периодическое обновление" (Periodic Update): Workflow может выполняться вечно, периодически запуская Activity (например, для синхронизации данных).

Best Practices

  • Идемпотентность Activity: Все Activity должны быть идемпотентными (повторный вызов с теми же параметрами не должен менять результат), так как Temporal гарантирует выполнение, но может повторно запустить Activity после сбоя.
  • Управление версиями Workflow: При изменении кода существующего Workflow используйте механизм версионирования (Workflow.GetVersion), чтобы новые выполнения использовали новую логику, а продолжающиеся — старую.
  • Таймауты и retry-политики: Всегда настраивайте разумные таймауты и политики повторов как на уровне Workflow, так и Activity.
  • Отделяйте бизнес-логику от оркестрации: Activity должна содержать чистую бизнес-логику, Workflow — только логику оркестрации (последовательность, условия, обработка ошибок).

Когда НЕ использовать Temporal?

  • Простые cron-задачи или синхронные вызовы API.
  • Обработка потоковых данных в реальном времени (используйте Apache Flink, Kafka Streams).
  • Когда вся команда ожидает no-code решения.

Полезные ресурсы