Skip to content

Distributed Execution Specification

Document ID: WF-012 Version: 1.1.0 Status: Draft. The WorkQueue/Worker/lease/partition machinery this document describes is real, tested library code in wovyr-workflow (§33’s measured baselines are real runs, not projections) — but it is not wired into the shipping wovyr-server binary. default_workflows_engine hardwires a single-process FileStore; there is no queue, no lease, no worker pool in the running server today. ADR-0010 ratified a single-node-appliance GA (Path A) specifically because of this gap — wiring this machinery onto the default path (env-selecting a PostgresStore, routing submitted workflows through the queue/lease path, a multi-replica correctness suite) is the v1.1 “Scale-Out” milestone — Track B of the Phase-3 ticket doc, gated on GA shipping first. Read this document as “what the library can do today, and what wiring it up will require,” not as a description of the running platform. Owner: Workflow Engine Team Last Updated: 2026-07-07


This document defines the Distributed Execution architecture for the Wovyr Workflow Engine.

Distributed Execution enables workflows to execute across multiple worker nodes while maintaining deterministic execution, fault tolerance, scalability, and consistency.

The subsystem supports:

  • Horizontal scaling
  • Worker clustering
  • Dynamic scheduling
  • Load balancing
  • Fault recovery
  • Lease management
  • Multi-region deployments
  • High availability

The Distributed Execution subsystem must provide:

  • Unlimited horizontal scaling
  • Fault tolerance
  • Worker independence
  • Deterministic execution
  • Automatic failover
  • Efficient resource utilization
  • Low scheduling latency
  • Replay compatibility

  1. Workers are stateless.
  2. Workflow state is never stored in worker memory permanently.
  3. Workers communicate only through infrastructure services.
  4. All execution state is durable.
  5. Failed workers never corrupt workflow state.
  6. Every workflow has a single active owner.
  7. Workers can join or leave the cluster at any time.

API Gateway
Workflow API Service
Workflow Scheduler
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Worker Node A Worker Node B Worker Node C
│ │ │
└─────────────────┼─────────────────┘
Event Bus
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Persistence Checkpointing Metrics

Cluster
+-------------------------------+
Scheduler Leader
+-------------------------------+
Worker Pool
Worker-1
Worker-2
Worker-3
Worker-4
Worker-N

Workers are homogeneous.


Each worker is responsible for:

  • Executing workflow activities
  • Reporting heartbeats
  • Creating checkpoints
  • Publishing events
  • Managing activity lifecycle
  • Recovering interrupted executions

Workers never directly communicate with each other.


Startup sequence:

Start Worker
Authenticate
Register
Receive Worker ID
Advertise Capabilities
Ready

Each worker publishes:

workerId:
hostname:
version:
cpu:
memory:
architecture:
region:
zone:
supportedActivities:
status:
heartbeatInterval:

Offline
Starting
Registering
Idle
Busy
Draining
Stopped

Workers periodically send heartbeats.

Heartbeat includes:

workerId:
timestamp:
activeExecutions:
cpuUsage:
memoryUsage:
queueLength:
leaseCount:

Missed heartbeats initiate failover.


A workflow execution is protected by a lease.

Scheduler
Lease Granted
Worker Executes
Heartbeat
Lease Renewed

Only the lease owner may execute a workflow.


If heartbeats stop:

Worker Crash
Lease Timeout
Lease Expired
Workflow Recovered
New Lease Granted

Scheduler considers:

  • Worker load
  • Queue depth
  • Activity affinity
  • Region
  • Available memory
  • CPU utilization
  • Tenant limits

Scheduling is deterministic.


Recovery sequence:

Worker Failure
Lease Expiration
Load Checkpoint
Replay Events
Assign New Worker
Resume Workflow

Supported algorithms:

  • Round Robin
  • Least Loaded
  • Least Active Executions
  • Resource Aware
  • Priority Aware
  • Region Aware

Default:

Least Loaded

Activities may request affinity.

Example:

activity:
affinity:
gpu: true
region: us-east
memory: high

Scheduler attempts to honor affinity.


Horizontal scaling:

High Queue Length
Provision Worker
Register Worker
Accept New Work

Scale-down uses graceful draining.


Draining procedure:

Busy
Draining
Reject New Activities
Finish Existing Work
Shutdown

No workflow interruption occurs.


Region A
Scheduler
Workers
────────────
Region B
Workers
────────────
Region C
Workers

Workflows may execute within preferred regions.


Locks protect:

  • Workflow execution
  • Checkpoint creation
  • State transitions
  • Compensation
  • Retry scheduling

Lock ownership follows lease ownership.


Consistency guarantees:

  • Single workflow owner
  • Ordered state transitions
  • Deterministic replay
  • Atomic checkpoint creation
  • Optimistic concurrency

Recovery process:

  1. Detect failure.
  2. Expire lease.
  3. Load latest checkpoint.
  4. Replay missing events.
  5. Acquire new lease.
  6. Resume execution.

Recovery must not duplicate completed work.


Workers communicate using events only.

Examples:

ActivityStarted
ActivityCompleted
WorkflowPaused
CheckpointCreated
RetryScheduled
LeaseExpired

Workers authenticate using:

  • mTLS
  • JWT
  • API Keys
  • Certificate-based identity

Authorization is enforced before lease assignment.


Metrics:

  • Active workers
  • Idle workers
  • Busy workers
  • Failed workers
  • Queue length
  • Scheduling latency
  • Lease renewals
  • Recovery count

Each worker logs:

workerId:
executionId:
workflowId:
activityId:
leaseId:
event:
timestamp:

MetricTarget
Worker registration< 500 ms
Lease acquisition< 20 ms
Scheduling latency< 50 ms
Failover detection< 10 sec
Workflow recovery< 500 ms
Heartbeat interval5 sec

pub trait Worker {
fn register(&self) -> Result<WorkerId>;
fn heartbeat(&self) -> Result<()>;
fn execute(
&self,
activity: ActivityExecution,
) -> Result<ActivityResult>;
}
pub trait LeaseManager {
fn acquire(
&self,
workflow: WorkflowId,
worker: WorkerId,
) -> Result<Lease>;
fn renew(
&self,
lease: LeaseId,
) -> Result<()>;
fn release(
&self,
lease: LeaseId,
) -> Result<()>;
}

engine-distributed/
├── cluster.rs
├── worker.rs
├── worker_registry.rs
├── lease_manager.rs
├── heartbeat.rs
├── scheduler_client.rs
├── load_balancer.rs
├── failover.rs
├── recovery.rs
├── affinity.rs
├── metrics.rs
└── mod.rs

  • Lease acquisition
  • Lease renewal
  • Worker registration
  • Heartbeat validation
  • Multi-worker execution
  • Failover recovery
  • Load balancing
  • Distributed scheduling
  • 10,000 workers
  • 1M concurrent workflows
  • Large cluster recovery
  • Scheduling throughput
  • Worker crash
  • Network partition
  • Scheduler restart
  • Region outage
  • Heartbeat loss
  • Database failure

RequirementTarget
Availability99.99%
Horizontal scalabilityUnlimited
Duplicate execution0
Recovery correctness100%
Lease consistency100%
Replay correctness100%

  • Workflow Overview
  • Execution Model
  • Scheduler
  • State Machine
  • Checkpointing
  • Retry Engine
  • Compensation Engine
  • Event Bus
  • Persistence Layer
  • Agent Runtime
  • Rust Crate Design

This section states the current, honest scaling envelope of the implemented distributed runtime — the leased WorkQueue + Worker model — and how to scale it out, rather than overstating it. It closes gap-closure item G6.

Executions are durably created by Engine::start, enqueued, and leased to one Worker at a time via a time-bounded lease; a crashed worker’s lease expires and another reclaims it (exactly-once activity effects via idempotent resume). Two queue backends:

  • InMemoryWorkQueue — single process. Entries live in a BTreeMap keyed by execution id; a lease takes the first ready entry by an early-exiting ordered scan (no per-call sort), so lease/remove is near-O(1) when leases are removed promptly.
  • PostgresStore as a WorkQueue — cross-process/node. Uses FOR UPDATE SKIP LOCKED so concurrent workers claim disjoint rows without blocking.

33.2 Partitioning (removing pool contention)

Section titled “33.2 Partitioning (removing pool contention)”

To let multiple worker pools scale horizontally without contending on one hot row range, the queue is sharded. Each execution is assigned a partition shard_of(id, total) (a stable FNV-1a hash mod total). A pool serves a PartitionAssignment (PartitionAssignment::for_pool(index, pool_count, total)), and WorkQueue::lease_sharded only considers executions in the pool’s owned partitions — so pools on disjoint partitions never lock the same rows. For the Postgres queue the shard is a column populated at enqueue (PostgresStore::with_partitions, indexed), so the SKIP LOCKED claim is filtered server-side (WHERE shard = ANY(...)). A Worker::with_partitions(assignment) joins one pool.

Correctness is covered by queue::tests::sharded_pools_lease_disjoint_executions (N pools over P partitions lease every execution exactly once, each only from its own partitions).

Assertion-style baselines from crates/wovyr-workflow/tests/perf.rs, trivial single-activity workflow, in-memory stores, single core, debug build on a developer machine (2026-06-29) — a software-overhead ceiling, not a distributed figure:

MetricMeasuredNotes
Engine throughput~23,600 executions/secstart → drive → complete, one core
Lease + remove~299,000 ops/secin-memory queue primitive

Release builds and real activity work shift these; the test asserts a conservative floor and prints the live number so regressions surface.

  • The single leased queue + SKIP LOCKED scales to many workers on one Postgres queue for moderate load. Partitioning (§33.2) extends this to multiple pools by removing cross-pool lock contention — the recommended first scale step.
  • Beyond that, the bottleneck becomes the single Postgres queue table itself. Splitting matching from history (a Temporal-style matching/history service tier) is out of scope by design — see ADR rationale in the gap analysis. The documented path is: shard the queue across pools → if needed, shard the queue table/Postgres → only then consider a dedicated matching tier. We publish the envelope rather than imply web-scale we have not built.

  • Multi-cluster federation
  • Cross-cloud execution
  • Geo-aware scheduling
  • Spot instance optimization
  • Predictive workload placement
  • AI-driven scheduling
  • Autonomous cluster healing

VersionDateDescription
1.0.02026-06-26Initial Distributed Execution Specification
1.1.02026-06-29Added §33 Scaling Envelope (G6): partitioning + measured baselines
1.2.02026-07-07RM-GA-P3 DOC-A2: added a top-level status note clarifying this machinery is tested library code not wired into the shipping wovyr-server binary — wiring it is the v1.1 “Scale-Out” milestone per ADR-0010