Durable Workflow Engine Architecture

Beyond Temporal — Snapshot-Based Execution

Updated

Durable workflow engines let you write multi-step processes that survive crashes, restarts, and deployments. The dominant approach — history replay, pioneered by Temporal — works but imposes a tax on every developer who touches workflow code: determinism constraints, payload size limits, history bloat, and activity ceremony. I solo-built an alternative in Rust — every crate, every SDK, every integration written by one person — that uses snapshot-based state persistence instead. No replay. No determinism constraints. O(1) resume from the last checkpoint.

Teams adopt Temporal because they need durable execution. Then they spend months building workarounds for its constraints. History replay means every workflow wake-up replays the entire event log — fine for short workflows, operationally expensive for long-running ones that hit the 50K event limit. Continue-as-new orchestration, state externalization, payload compression codecs, custom search attribute registration — I have measured over 2,400 lines of workaround code in a production Temporal codebase. That is 10 percent of the entire codebase dedicated to fighting the framework.

The snapshot approach is simpler: persist the current state to a Postgres row after each step. On resume, load the row and continue. No replay, no history limits, no determinism constraints. Developers write normal code — Date.now(), Math.random(), external API calls — all work without patched() wrappers or version markers. The engine handles retries, timeouts, parallel execution, and structured concurrency. The developer handles the business logic.

The two architectures solve the same problem — workflows that survive crashes — with very different costs for the teams that build on them.

History replay (Temporal)Snapshot-based (Orch8)
Resume after crashReplays the entire event history — O(N) per wake-upLoads the last snapshot — O(1), no replay
Determinism constraintsRequired: patched() wrappers and version markers; no plain Date.now() or Math.random()None — normal code and normal libraries work
Long-running workflows50K event limit forces continue-as-new orchestrationNo event limit — snapshots stay constant-size
Inspecting workflow stateSignal and query handlers, custom search attributesStandard JSONB queries against Postgres
Large payloadsSize limits push teams to externalize state and add compression codecsState persisted as JSONB after each step
Local testingRequires a running Temporal serverEmbedded SQLite mode with identical behavior

Measured in one production Temporal codebase: 2,400+ lines — roughly 10% of the code — existed only to work around the framework's replay constraints.

  1. 10-Crate Workspace Architecture

    Orch8 Engine

    Designed a Rust workspace with clean separation across 10 crates: orch8-types (shared domain types), orch8-storage (Postgres + SQLite via SQLx), orch8-engine (core execution logic), orch8-api (Axum REST with OpenAPI via utoipa), orch8-grpc (Tonic gRPC interface), orch8-server (runtime composition), orch8-cli (Clap-based CLI), orch8-publisher (event publishing), orch8-push (push notifications), orch8-mobile (mobile API layer). Each crate compiles independently. The engine crate has zero knowledge of HTTP or gRPC — it operates on trait abstractions that the server crate wires together.

  2. Snapshot-Based State Persistence

    Orch8 Engine

    Implemented O(1) resume by persisting workflow state as JSONB in Postgres after each step completion. No event log to replay. State is directly queryable — GET /instances/{id}/state returns the full context without signal handlers or query boilerplate. Filter instances by any field via standard Postgres JSONB queries. Embedded SQLite mode for testing with identical behavior.

  3. Multi-Language SDK Design

    Orch8 Engine

    Built Node.js and Python SDKs that communicate with the Rust engine via gRPC. Steps are plain functions — no activity ceremony, no central registry, no manual error classification. The SDK handles connection management, retry coordination, and heartbeating. Workers register step handlers by convention and the engine dispatches work with per-resource rate limiting and configurable concurrency.

RustTokioAxumTonicSQLxPostgreSQLSQLitegRPCProtobufNATSWasmtimePrometheusNode.js SDKPython SDK

The workflow engine is built in Rust because durability demands correctness guarantees that garbage-collected languages cannot provide at the systems level. See why Rust for mission-critical infrastructure.

Rust for Mission-Critical Systems Why Rust When Failure Is Not an Option

Workflow engines generate events that downstream systems consume in real time. See how I build the streaming infrastructure that connects orchestration to live dashboards.

Real-Time Systems WebSockets, Message Queues, and Live Data

The storage layer under a workflow engine must handle high-frequency writes and analytical reads. See how I design data layers for systems that cannot lose state.

Database Architecture and Performance Designing Data Systems That Scale

What is a durable workflow engine and why does it matter?

A durable workflow engine lets you write multi-step processes that survive crashes, restarts, and deployments — the engine persists progress so work resumes instead of being lost. The dominant approach, history replay pioneered by Temporal, works but taxes every developer with determinism constraints, payload size limits, history bloat, and activity ceremony. The alternative is snapshot-based persistence: save current state after each step and resume in O(1) from the last checkpoint, with no replay and no determinism rules.

When should a team build on Temporal versus a snapshot-based engine?

Temporal's history replay is fine for short workflows but operationally expensive for long-running ones that hit the 50K event limit, forcing continue-as-new orchestration, state externalization, and payload compression codecs. Oleksii measured over 2,400 lines of workaround code in one production Temporal codebase — 10 percent of the codebase fighting the framework. A snapshot-based engine suits teams that want developers writing normal code, with Date.now(), Math.random(), and external API calls working without patched() wrappers or version markers.

What production experience does Oleksii Vasylenko have building workflow engines?

Oleksii solo-built Orch8, a complete durable workflow engine in Rust — every crate, SDK, and integration written by one person. The 10-crate workspace separates types, storage (Postgres and SQLite via SQLx), core engine, Axum REST API with OpenAPI, Tonic gRPC, server runtime, CLI, event publisher, push notifications, and mobile API layer. He also built Node.js and Python SDKs that communicate with the engine over gRPC, with per-resource rate limiting and configurable concurrency.

What goes wrong when teams adopt durable execution frameworks?

Teams adopt durable execution for reliability, then spend months building workarounds for the framework's constraints. With history replay, every workflow wake-up replays the entire event log, and long-running workflows hit event limits that force continue-as-new orchestration, state externalization, and custom search attribute registration. Determinism constraints also infect ordinary code: developers must wrap nondeterministic calls and manage version markers. The result Oleksii measured was 2,400-plus lines of framework-fighting code in a single production codebase.

How can a team get help moving off Temporal or fixing workflow architecture?

Oleksii has built the alternative architecture and measured the difference against Temporal in production code. His snapshot-based design persists workflow state as JSONB in Postgres after each step — O(1) resume, directly queryable state via standard JSONB queries, no signal handlers or query boilerplate, and an embedded SQLite mode for testing with identical behavior. Teams spending more time fighting their workflow framework than writing business logic can contact him through ovasylenko.com.

Drowning in Temporal workarounds?

History replay, continue-as-new, payload compression, determinism constraints — if your team spends more time fighting the framework than writing business logic, there is a better architecture. I have built the alternative and I have measured the difference. If you need durable execution without the operational tax, let’s talk.

Discuss your workflow architecture