Пособие по 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.
Продвинутые возможности и паттерны
- Работа с очередями (Queues): Каждый Workflow и Activity Task помещается в свою очередь, что обеспечивает масштабируемость и приоритизацию.
- Паттерн "Saga": Temporal — идеальный инструмент для реализации долгоживущих саг в микросервисной архитектуре, где важна согласованность данных.
- Паттерн "Работа с человеком в цикле" (Human-in-the-loop): Workflow может приостановиться, ожидая сигнала (например, одобрения менеджера), и продолжить автоматически после его получения.
- Паттерн "Периодическое обновление" (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 решения.
Полезные ресурсы
- Официальная документация: docs.temporal.io
- Примеры на GitHub: github.com/temporalio/samples-go
- Temporal UI для мониторинга: обычно на порту 8080
- Сообщество в Slack: temporalio.slack.com