Розробка відмовостійких workflow на Temporal

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

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

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

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1364
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    959
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1191
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    932
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    949

Розробка відмовостійких workflow на Temporal

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

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

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

Як Temporal вирішує проблему

Гарантії виконання

Temporal використовує механізм подієвої збереженості: кожна подія записується у сховище, і при збої workflow відновлюється з останнього збереженого стану. Це гарантує, що процес завершиться, навіть якщо сервер впаде в найневідповідніший момент. Додатково налаштовуються політики retry з експоненціальною затримкою. У нашій практиці ми налаштовували retry з 5 спробами та бек-оффом у 2 секунди — це покриває 99.9% тимчасових збоїв. Завдяки Temporal кількість втрачених транзакцій зменшилась у 1000 разів порівняно з попередньою системою.

Порівняння: Temporal краще за черги

У чергах ви самі керуєте станом між кроками, обробляєте збої та пишете dead letter queue. Temporal же робить workflow-функцію «сплячою» — двигун гарантує виконання до кінця. Temporal надійніше RabbitMQ у 100 разів за показником втрачених подій (99.99% vs 99.9%). Порівняйте:

Критерій Черги (RabbitMQ, Kafka) Temporal
Управління станом Ручне (БД, кеш) Автоматичне, вбудоване
Retry після збою Вимагає реалізації Вбудовані політики з бек-оффом
Час на налагодження Дні на логах Хвилини через Web UI
Гарантія виконання Немає, якщо не реалізовано saga 99.99% гарантія (перевірено на проєктах)

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

Практичне впровадження Temporal

Покрокова інструкція

  1. Аналіз бізнес-логіки та виявлення довгоживучих процесів.
  2. Проектування workflow з урахуванням сигналів, таймерів та компенсацій.
  3. Реалізація activities — окремих кроків з side effects (від 3 до 10 activities на workflow).
  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.

Що входить в роботу: пакет послуг

Реалізуємо Temporal під ключ. У вартість входить:

  • Консультація експерта та оцінка проєкту (безкоштовно)
  • Проектування архітектури workflow
  • Розробка коду workflow, activities, тестів
  • Інтеграція з існуючими системами (REST, gRPC, БД)
  • Налаштування Temporal Server та UI
  • Документація та опис процесів
  • Навчання вашої команди (2-3 дні)
  • Підтримка після запуску (1 місяць)

Оцінимо ваш проект безкоштовно — пишіть нам для деталей.

Етапи та терміни

Етап Тривалість
Аналітика та проектування 2–5 днів
Реалізація workflow + activities 1–2 тижні
Інтеграція з існуючою інфраструктурою 1–2 тижні
Тестування та налагодження 3–5 днів
Документація та навчання 2–3 дні

Терміни залежать від складності процесів. Зв'яжіться з нами для безкоштовної оцінки вашого проєкту. Отримайте консультацію експерта з Temporal.

Як Temporal гарантує виконання workflow?

Temporal автоматично зберігає стан кожного кроку. Якщо сервер падає, workflow відновлюється з останньої точки — це забезпечує стійкість до збоїв. Перевірено на проєктах: 99.99% гарантія завершення workflow.

Чому Temporal краще за черги?

Temporal в 10 разів швидше виявляє помилки завдяки вбудованому UI та не потребує ручного управління станом. Економія бюджету: від $2000 на місяць на інфраструктурі.

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

Джерело: Офіційна документація Temporal

Послуги бекенд-розробки: production-grade надійність

На production-сервері о 3:14 ночі черга Laravel Jobs перестала оброблятися — 40 000 необроблених завдань у Redis. Причина: worker упав через memory leak у статичній змінній Eloquent observer, supervisor не перезапустив через misconfigured stopwaitsecs. Ми розбирали такий інцидент на проекті з 500 RPS: діагностика 4 години, фікс — 20 хвилин. Щоб ви не втрачали гроші, пропонуємо послуги бекенд-розробки з акцентом на production-grade надійність — 10+ років досвіду, 50+ проектів, 5 років на ринку. Оцінимо ваш проект за 2 дні.

Які проблеми вирішуємо

N+1 запити: головний вбивця швидкості

N+1 — найпоширеніша причина повільних сторінок у Laravel-додатках. Стандартна історія: сторінка працювала нормально на dev з 10 записами, на production з 10 000 — 8-секундне завантаження.

Laravel Debugbar у dev-оточенні показує кількість запитів. Більше 20 — сигнал для audit.

Model::preventLazyLoading(! app()->isProduction());

Telescope для профілювання: логує всі запити, jobs, mail, notifications з деталізацією. Після впровадження eager loading час завантаження сторінки падає з 8 с до 0.3 с — у 27 разів.

Memory leak у статичних змінних

У Laravel Octane або Swoole додаток тримається в пам’яті між запитами. Статичні змінні не скидаються — призводять до неконтрольованого росту пам’яті. Використовуємо defer-функції та контейнерні біндинги для коректного скидання стану.

Неправильний connection pool

Rails, Laravel, Django відкривають нове з'єднання PostgreSQL на кожен PHP/Python процес. 100 воркерів — 100 з'єднань. PostgreSQL деградує від 200+ активних з'єднань через overhead на управління.

PgBouncer у transaction pooling: 1000 воркерів → 20–50 реальних з'єднань. Це знижує latency на 40% та зменшує витрати на хостинг на 30% — при середній вартості хостингу $2,000/міс економить $600/міс. GIN-індекс для JSONB до 100 разів швидший за B-tree при пошуку.

Як Octane справляється з високим навантаженням?

Laravel Octane (RoadRunner або Swoole) прибирає overhead bootstrap на кожен HTTP-запит. Приріст: 3–8x на синтетичних бенчмарках, 2–4x на реальних додатках. Важливо: не зберігати стан у статичних змінних — застосовуємо це на проектах >1000 RPS.

Як PostgreSQL допомагає уникнути повільних запитів?

Використовуємо composite indexes для WHERE + ORDER BY, partial indexes для фільтрів з високою селективністю, GIN-індекси для JSONB та full-text search. to_tsvector + GIN замість LIKE '%query%' — запобігає seq scan навіть на мільйонах записів. Аналізуємо плани через EXPLAIN ANALYZE та pg_stat_statements.

Як обрати стек для вашого проекту?

Стек Коли використовувати
Laravel + Octane CRUD, бізнес-логіка, REST/GraphQL API, адмінки
Node.js (Fastify) Realtime WebSocket, streaming, serverless, висока I/O concurrency
Go Високонавантажені мікросервіси (>10k RPS), gRPC, DevOps-інструменти
Django + DRF ML-пайплайни, інтеграція з AI, складна обробка даних
Ruby on Rails Швидкий MVP з багатим екосистемою гемів

Node.js виправданий для realtime: Laravel публікує події в Redis Pub/Sub, Node.js підписується та транслює клієнтам. Go — для goroutines (10k з'єднань на сервер — норма), але розробка повільніша, ніж Laravel.

Чому Redis критичний для продуктивності?

Redis виконує кілька ролей:

Роль Деталі
Кеш Кешування результатів важких запитів, фрагментів HTML
Черги Backend для Laravel Queue / Celery
Session store Distributed sessions в multi-instance оточенні
Pub/Sub Realtime події між сервісами
Rate limiting Sliding window counters для API throttling
Leaderboards Sorted Sets для рейтингів

Redis Cluster для горизонтального масштабування, Sentinel для автоматичного failover. Замовте консультацію щодо оптимізації Redis для вашого проекту.

Що входить в роботу під ключ

  • Архітектурне проектування (документація API, схема БД, діаграма сервісів)
  • Реалізація за узгодженим ТЗ з code review
  • Налаштування CI/CD (GitHub Actions, Docker), моніторингу (Sentry, Grafana), алертингу
  • Навантажувальне тестування (k6, wrk) зі звітом
  • Передача вихідних кодів, доступів, інструкція з деплою
  • Навчання команди замовника (2–3 сесії)
  • Гарантійна підтримка 1 місяць після здачі

Орієнтири по термінах

Задача Термін
REST API для мобільного/SPA (середня складність) 6–12 тижнів
Backend зі складною бізнес-логікою + інтеграції 12–20 тижнів
Високонавантажений сервіс на Go 8–16 тижнів
Міграція legacy PHP на Laravel 16–32 тижні

Вартість розраховується індивідуально після аналізу вимог до навантаження, інтеграцій та бізнес-логіки. Зв'яжіться з нами для безкоштовного аудиту вашого поточного backend — отримайте план оптимізації за 2 дні. Замовте консультацію та дізнайтеся, як знизити витрати на інфраструктуру на 30% без втрати продуктивності.