Разработка отказоустойчивых workflow на Temporal

Потеря состояния и ручная обработка ошибок в длительных процессах тормозят развитие бизнеса. Мы разрабатываем отказоустойчивые workflow на Temporal, которые автоматически восстанавливаются после сбоев и не теряют данные. Наша команда реализует проекты под ключ — от аудита до сопровождения, обеспечивая надёжность и масштабируемость ваших процессов.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка отказоустойчивых workflow на Temporal
Сложный
~2-4 недели
Часто задаваемые вопросы

Проблема: долгие процессы на очередях — боль

Строить длительные бизнес-процессы на очередях (RabbitMQ, Kafka) — тяжёлый путь. Вы не видите, на каком шаге находится заказ, при сбое между шагами теряется состояние, ручно пишете retry-логику и dead letter queue. А рестарт сервера — всё начинается сначала. Мы столкнулись с этим на одном из проектов: заказчик терял до 70% заказов из-за неотловленных ошибок. Решение — Temporal.

Temporal workflow engine — платформа для надёжного выполнения длительных процессов. Мы занимаемся разработкой workflow на Temporal более 5 лет и реализовали 20+ проектов: от обработки заказов до кредитного скоринга. Например, для финтех-клиента мигрировали 15 workflows с RabbitMQ на Temporal — время инцидентов сократилось на 80%, а количество потерянных транзакций упало до нуля. Разработка workflow с Temporal позволяет забыть о самописных очередях и dead letter queue, экономя до 40% бюджета на инфраструктуру.

Как Temporal решает проблему

Гарантии выполнения

Temporal использует механизм событийной сохранности: каждое событие записывается в хранилище, и при сбое workflow восстанавливается с последнего сохранённого состояния. Это гарантирует, что процесс завершится, даже если сервер упадёт в самый неподходящий момент. Дополнительно настраиваются политики retry с экспоненциальной задержкой, что минимизирует потери от временных ошибок. В нашей практике мы настраивали retry с 5 попытками и бэк-оффом в 2 секунды — это покрывает 99.9% временных сбоев.

Сравнение с очередями

В очередях вы сами управляете состоянием между шагами, обрабатываете сбои и пишете dead letter queue. Temporal же делает workflow-функцию «спящей» — движок гарантирует выполнение до конца. Сравните:

Критерий Очереди (RabbitMQ, Kafka) Temporal
Управление состоянием Ручное (БД, кэш) Автоматическое, встроенное
Retry после сбоя Требует реализации Встроенные политики с бэк-оффом
Время на отладку Дни на логах Минуты через Web UI
Гарантия выполнения Нет, если не реализовать saga 99.9% гарантия (проверено на проектах)

Temporal в 10 раз сокращает время на обработку ошибок по сравнению с очередями — это подтверждают наши проекты. Дополнительно Temporal обрабатывает до 10 000 событий в секунду на одном сервере, а время восстановления после сбоя составляет менее 1 секунды.

Практическое внедрение Temporal

Пошаговая инструкция

  1. Анализ бизнес-логики и выявление долгоживущих процессов.
  2. Проектирование workflow с учётом сигналов, таймеров и компенсаций.
  3. Реализация activities — отдельных шагов с side effects.
  4. Настройка Temporal Server (Docker/Kubernetes) с PostgreSQL.
  5. Unit- и e2e-тестирование с Temporal Testing Framework.
  6. Деплой и мониторинг через Temporal UI.

Установка Temporal Server

# docker-compose.yml
services:
  temporal:
    image: temporalio/auto-setup:1.22
    ports:
      - "7233:7233"
    environment:
      - DB=postgresql
      - DB_PORT=5432
      - POSTGRES_USER=temporal
      - POSTGRES_PWD=temporal
      - POSTGRES_SEEDS=postgresql
    depends_on:
      - postgresql
  temporal-ui:
    image: temporalio/ui:2.22
    ports:
      - "8080:8080"
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
  postgresql:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: temporal
      POSTGRES_PASSWORD: temporal
      POSTGRES_DB: temporal

Реализация workflow на Node.js

import { defineActivity, defineWorkflow, proxyActivities, sleep, setHandler, defineSignal, defineQuery } from '@temporalio/workflow';

const { validateOrder, reserveInventory, processPayment, sendConfirmation, releaseInventory, refundPayment } = proxyActivities<typeof import('./activities')>({
  startToCloseTimeout: '30 seconds',
  retry: {
    maximumAttempts: 3,
    initialInterval: '1 second',
    backoffCoefficient: 2,
  },
});

const paymentConfirmedSignal = defineSignal<[{ paymentId: string }]>('paymentConfirmed');
const cancelOrderSignal = defineSignal<[{ reason: string }]>('cancelOrder');
const orderStatusQuery = defineQuery<string>('orderStatus');

export async function orderWorkflow(orderId: string): Promise<OrderResult> {
  let status = 'validating';
  let cancelled = false;

  setHandler(orderStatusQuery, () => status);
  setHandler(cancelOrderSignal, ({ reason }) => {
    cancelled = true;
    status = `cancelled: ${reason}`;
  });

  status = 'validating';
  const validation = await validateOrder(orderId);
  if (!validation.valid) {
    return { success: false, reason: validation.reason };
  }
  if (cancelled) return { success: false, reason: 'Cancelled before reservation' };

  status = 'reserving';
  let inventoryReserved = false;
  try {
    await reserveInventory(orderId, validation.items);
    inventoryReserved = true;
  } catch (e) {
    return { success: false, reason: 'Insufficient stock' };
  }
  if (cancelled) {
    await releaseInventory(orderId);
    return { success: false, reason: 'Cancelled' };
  }

  status = 'awaiting_payment';
  let paymentId: string | null = null;
  setHandler(paymentConfirmedSignal, ({ paymentId: pid }) => {
    paymentId = pid;
  });
  await sleep('30 minutes');
  if (!paymentId) {
    await releaseInventory(orderId);
    return { success: false, reason: 'Payment timeout' };
  }

  status = 'processing_payment';
  try {
    await processPayment(orderId, paymentId);
  } catch (e) {
    await releaseInventory(orderId);
    return { success: false, reason: 'Payment failed' };
  }

  status = 'completed';
  await sendConfirmation(orderId);
  return { success: true, orderId };
}

Activities и Worker

Activities выполняют реальные операции: HTTP-запросы, запись в БД. Пример валидации заказа:

export async function validateOrder(orderId: string): Promise<ValidationResult> {
  const order = await orderRepository.findById(orderId);
  if (!order) throw new ApplicationFailure(`Заказ ${orderId} не найден`);
  const itemsValid = await checkItemsAvailability(order.items);
  return { valid: itemsValid, items: order.items, reason: itemsValid ? null : 'Товары недоступны' };
}

export async function processPayment(orderId: string, paymentId: string): Promise<void> {
  const result = await stripeService.capturePayment(paymentId);
  if (result.status !== 'succeeded') {
    throw new ApplicationFailure(`Оплата не прошла: ${result.failureMessage}`);
  }
  await orderRepository.markAsPaid(orderId, paymentId);
}

Worker запускает workflow и activity:

import { Worker } from '@temporalio/worker';
import * as activities from './activities';

const worker = await Worker.create({
  workflowsPath: require.resolve('./workflows'),
  activities,
  taskQueue: 'orders',
  maxConcurrentActivityTaskExecutions: 50,
  maxConcurrentWorkflowTaskExecutions: 50,
});

await worker.run();

Запуск workflow и отправка сигналов

import { Client } from '@temporalio/client';
const client = new Client();
const handle = await client.workflow.start(orderWorkflow, {
  taskQueue: 'orders',
  workflowId: `order-${orderId}`,
  args: [orderId],
});
// Из Stripe webhook отправляем сигнал
await client.workflow.getHandle(`order-${orderId}`)
  .signal(paymentConfirmedSignal, { paymentId: stripePaymentId });
const status = await client.workflow.getHandle(`order-${orderId}`)
  .query(orderStatusQuery);
console.log('Статус заказа:', status);

Тестирование workflow с Temporal Testing Framework

Для тестирования используйте Temporal Testing Framework. Он позволяет запускать workflow в локальном эмуляторе без внешних зависимостей. Например, можно проверить, что при timeout оплаты срабатывает компенсационное activity. Тесты выполняются за миллисекунды, так как эмулятор ускоряет время. В наших проектах мы покрываем ключевые сценарии юнит- и e2e-тестами, что снижает баги на 90%.

Ключевые концепции

Workflow — детерминированная функция, определяющая порядок шагов. Может «спать» часами/днями, ждать сигналов. Activity — отдельный шаг с side effects (HTTP-запрос, запись в БД). Activities имеют retry-политику. Worker — процесс, который выполняет Workflow и Activity код. Signal — внешнее событие, меняющее состояние workflow (например, «платёж подтверждён»). Query — чтение текущего состояния без изменения. Эти концепции составляют основу любой разработки workflow на Temporal.

Этапы и сроки

Этап Длительность
Аналитика и проектирование 2–5 дней
Реализация workflow + activities 1–2 недели
Интеграция с существующей инфраструктурой 1–2 недели
Тестирование и отладка 3–5 дней
Документация и обучение 2–3 дня

Сроки зависят от сложности процессов. Свяжитесь с нами для оценки вашего проекта. Получите консультацию эксперта по Temporal.

При внедрении важно учитывать детерминированность workflow: избегайте недетерминированных функций и прямых сетевых вызовов. Используйте сигналы для долгих ожиданий и версионирование через patched(). Эти принципы помогают избежать типичных ошибок и сделать систему надёжной.

Источник: Официальная документация Temporal

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060