Workflows
Workflows
Section titled “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?
Section titled “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
Section titled “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)endThe 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
Section titled “Workflow Patterns”Saga Pattern
Section titled “Saga Pattern”Compensate on failure:
local funcs = require("funcs")
local inventory = funcs.call("app.inventory:reserve", items)if inventory.error then return nil, inventory.errorend
local payment = funcs.call("app.payments:charge", amount)if payment.error then funcs.call("app.inventory:release", inventory.id) return nil, payment.errorend
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.errorend
return {inventory = inventory, payment = payment, shipping = shipping}Waiting for Signals
Section titled “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)endWhen to Use What
Section titled “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
Section titled “Starting Workflows”Workflows are spawned the same way as processes - using process.spawn() with a different host:
-- Spawn workflow on temporal workerlocal pid = process.spawn("app.workflows:order_processor", "app:temporal_worker", order_data)
-- Send signals to workflowprocess.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
Section titled “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: 10Workflows don’t use supervision trees - they’re automatically managed by the workflow provider (Temporal). The provider handles persistence, retries, and recovery.
Configuration
Section titled “Configuration”Process definition (spawned dynamically):
- name: order_processor kind: workflow.lua source: file://order_processor.lua method: main modules: - funcs - timeWorkflow provider:
- name: temporal_worker kind: temporal.worker client: app:temporal_client task_queue: "orders" lifecycle: auto_start: trueSee Temporal for production workflow infrastructure.
See Also
Section titled “See Also”- Functions - Stateless request handling
- Process Model - Stateful background work
- Supervision - Process restart policies