Перейти к содержимому

Workflows

Workflows — устойчивые, долгоживущие операции, которые переживают падения и перезапуски. Они обеспечивают гарантии надёжности для критических бизнес-процессов: платежей, выполнения заказов, многошаговых согласований.

Функции эфемерны — если хост падает, выполняемая работа теряется. Workflows сохраняют состояние:

АспектФункцииWorkflows
СостояниеВ памятиПерсистентное
ПадениеПотеря работыВозобновление
ДлительностьСекунды-минутыЧасы-месяцы
ЗавершениеBest effortГарантированное

Код workflow выглядит как обычный Lua:

local funcs = require("funcs")
local time = require("time")
local result = funcs.call("app.api:charge_card", payment)
time.sleep("24h")
local status = funcs.call("app.api:check_status", result.id)
if status == "failed" then
funcs.call("app.api:refund", result.id)
end

Движок workflow перехватывает вызовы и записывает результаты. Если процесс падает, выполнение воспроизводится из истории — тот же код, те же результаты.

Wippy автоматически обеспечивает детерминизм. Операции вроде funcs.call(), time.sleep(), uuid.v4() и time.now() перехватываются, их результаты записываются. При воспроизведении возвращаются записанные значения вместо повторного выполнения.

Компенсация при сбое:

local funcs = require("funcs")
local inventory = funcs.call("app.inventory:reserve", items)
if inventory.error then
return nil, inventory.error
end
local payment = funcs.call("app.payments:charge", amount)
if payment.error then
funcs.call("app.inventory:release", inventory.id)
return nil, payment.error
end
local shipping = funcs.call("app.shipping:create", order)
if shipping.error then
funcs.call("app.payments:refund", payment.id)
funcs.call("app.inventory:release", inventory.id)
return nil, shipping.error
end
return {inventory = inventory, payment = payment, shipping = shipping}

Ожидание внешних событий (решений по согласованию, вебхуков, действий пользователя):

local funcs = require("funcs")
funcs.call("app.approvals:submit", request)
local inbox = process.inbox()
local msg = inbox:receive() -- блокируется до прихода сигнала
if msg.approved then
funcs.call("app.orders:fulfill", request.order_id)
else
funcs.call("app.notifications:send_rejection", request)
end
СценарийВыбор
Обработка HTTP-запросовФункции
Трансформация данныхФункции
Фоновые задачиПроцессы
Состояние пользовательской сессииПроцессы
Real-time сообщенияПроцессы
Обработка платежейWorkflows
Выполнение заказовWorkflows
Многодневные согласованияWorkflows

Workflows порождаются так же, как процессы — через process.spawn() с другим хостом:

-- Spawn workflow на temporal worker
local pid = process.spawn("app.workflows:order_processor", "app:temporal_worker", order_data)
-- Отправка сигналов в workflow
process.send(pid, "update", {status = "approved"})

С точки зрения вызывающего API идентичен. Разница в хосте: workflows выполняются на temporal.worker, а не на process.host.

Когда workflow порождает потомков через process.spawn(), они становятся дочерними workflows на том же провайдере, сохраняя гарантии надёжности.

Процессы могут работать как супервизируемые сервисы через process.service:

# Определение процесса
- name: session_handler
kind: process.lua
source: file://session_handler.lua
method: main
# Супервизируемый сервис, оборачивающий процесс
- name: session_manager
kind: process.service
process: app:session_handler
host: app:processes
lifecycle:
auto_start: true
restart:
max_attempts: 10

Workflows не используют деревья супервизии — ими автоматически управляет провайдер workflows (Temporal). Провайдер обрабатывает персистентность, повторы и восстановление.

Определение процесса (порождается динамически):

- name: order_processor
kind: workflow.lua
source: file://order_processor.lua
method: main
modules:
- funcs
- time

Провайдер workflows:

- name: temporal_worker
kind: temporal.worker
client: app:temporal_client
task_queue: "orders"
lifecycle:
auto_start: true

См. Temporal для продакшен-инфраструктуры workflows.