Workflows
Workflows are durable, long-running operations that survive crashes and restarts. They provide reliability guarantees for critical business processes like payments, order fulfillment, and multi-step approvals.
Why Workflows?
Functions are ephemeral - if the host crashes, in-flight work is lost. Workflows persist their state:
| Aspect | Functions | Workflows |
|---|---|---|
| State | In memory | Persisted |
| Crash | Lost work | Resumes |
| Duration | Seconds to minutes | Hours to months |
| Completion | Best effort | Guaranteed |
How Workflows Work
Workflow code looks like regular Lua code:
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
The workflow engine intercepts calls and records results. If the process crashes, execution replays from history - same code, same results.
funcs.call(), time.sleep(), uuid.v4(), and time.now() are intercepted and their results recorded. On replay, recorded values are returned instead of re-executing.
Workflow Patterns
Saga Pattern
Compensate on failure:
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}
Waiting for Signals
Wait for external events (approval decisions, webhooks, user actions):
local funcs = require("funcs")
funcs.call("app.approvals:submit", request)
local inbox = process.inbox()
local msg = inbox:receive() -- blocks until signal arrives
if msg.approved then
funcs.call("app.orders:fulfill", request.order_id)
else
funcs.call("app.notifications:send_rejection", request)
end
When to Use What
| Use Case | Choose |
|---|---|
| HTTP request handling | Functions |
| Data transformation | Functions |
| Background jobs | Processes |
| User session state | Processes |
| Real-time messaging | Processes |
| Payment processing | Workflows |
| Order fulfillment | Workflows |
| Multi-day approvals | Workflows |
Starting Workflows
Workflows are spawned the same way as processes - using process.spawn() with a different host:
-- Spawn workflow on temporal worker
local pid = process.spawn("app.workflows:order_processor", "app:temporal_worker", order_data)
-- Send signals to workflow
process.send(pid, "update", {status = "approved"})
From the caller's perspective, the API is identical. The difference is the host: workflows run on a temporal.worker instead of a process.host.
process.spawn(), they become child workflows on the same provider, maintaining durability guarantees.
Failure and Supervision
Processes can run as supervised services using process.service:
# Process definition
- name: session_handler
kind: process.lua
source: file://session_handler.lua
method: main
# Supervised service wrapping the process
- name: session_manager
kind: process.service
process: app:session_handler
host: app:processes
lifecycle:
auto_start: true
restart:
max_attempts: 10
Workflows don't use supervision trees - they're automatically managed by the workflow provider (Temporal). The provider handles persistence, retries, and recovery.
Configuration
Process definition (spawned dynamically):
- name: order_processor
kind: workflow.lua
source: file://order_processor.lua
method: main
modules:
- funcs
- time
Workflow provider:
- name: temporal_worker
kind: temporal.worker
client: app:temporal_client
task_queue: "orders"
lifecycle:
auto_start: true
See Temporal for production workflow infrastructure.
See Also
- Functions - Stateless request handling
- Process Model - Stateful background work
- Supervision - Process restart policies