SD System Design In Depth
0%
lesson system-designworkflowsscheduling

DAG workflow orchestration

Module 4.2: Asynchronous Workflows & Partitioned Logs Updated Sep 17, 2026
📄 Cheat Sheet
Intro to Temporal Architecture: Workflow Engine
Temporal Intro to Temporal Architecture: Workflow Engine Watch on YouTube ↗

Temporal's architecture talk explains the event-sourced history, task queues, workers and deterministic replay, the exact mechanism this lesson centres on. The current Devoxx microservices talk is off-topic.

0:00 / --:--

Under the Hood: Orchestrating Complex Business Processes

Real-world engineering workflows (e.g. customer onboarding, food delivery fulfillment, ML model training pipelines) consist of multiple steps that must execute across heterogeneous services. These steps have dependencies forming a Directed Acyclic Graph (DAG).

The Temporal Event-Sourced Orchestration Architecture

flowchart TD Client["Client: StartOrderWorkflow()"] --> Cluster["Temporal Cluster (Orchestrator)"] subgraph HistoryEngine ["Durable Event Sourcing History Engine"] Cluster --> History[("Append-Only Execution History Log")] end subgraph WorkerFleet ["Distributed Worker Fleet"] Cluster -->|"Task: ChargeCard"| W1["Payment Worker"] W1 -->|"Result: Success"| Cluster Cluster -->|"Task: ReserveInventory"| W2["Inventory Worker"] W2 -->|"Result: Failed"| Cluster Cluster -->|"Compensating Task: RefundCard"| W1 end

Under the Hood: Deterministic Workflow Replay

Traditional orchestrators store current state in database tables (e.g. step = 'STEP_3'). Modern engines like Temporal and Cadence use Event Sourcing:

  • Workflows are written as standard code (Go, TypeScript, Java). Workers normally keep running workflows cached in memory and apply only new events. When a worker fails or restarts, or a cached workflow is evicted, a worker rebuilds the workflow state by replaying the recorded event history from the beginning.
  • During replay, previously executed external calls (Activities) are not re-executed; their recorded results are returned instantaneously from the history log.
  • The Determinism Rule: Workflow code must be 100% deterministic (no random UUID generation, direct system clock reads, or direct HTTP calls inside the workflow function). Non-deterministic operations must reside in Activities, or use the SDK's deterministic equivalents (for example workflow.Now and workflow.SideEffect in Go, Workflow.currentTimeMillis() and Workflow.randomUUID() in Java).

Worked example: an order saga with compensation

flowchart TD A["Start order workflow"] --> B["Charge card"] B -->|"ok"| C["Reserve inventory"] C -->|"ok"| D["Create shipment"] D -->|"ok"| E["Done"] C -->|"out of stock"| F["Refund card"] D -->|"carrier down after 5 retries"| G["Release inventory"] G --> F F --> H["Mark order failed"]

The Temporal history for a failure path might read: WorkflowStarted, ActivityScheduled ChargeCard, ActivityCompleted ChargeCard (txn t_55), ActivityScheduled ReserveInventory, ActivityFailed ReserveInventory (OutOfStock), ActivityScheduled RefundCard, ActivityCompleted RefundCard, WorkflowCompleted (failed). If the worker crashes after ChargeCard completes, a new worker replays the history: the ChargeCard call returns t_55 from history without charging again, and execution continues at ReserveInventory.

Engine comparison

EngineModelBest forState storageWatch out for
AirflowPython-defined static DAGs, scheduled runsBatch ETL, ML pipelinesMetadata DB of task statesScheduler latency of seconds. Not for per-request flows
Temporal / CadenceWorkflows as code, event-sourced replayLong-running business processes, sagasHistory per workflow (Cassandra, Postgres, MySQL)Determinism rules, history size limits (about 50,000 events), versioning
AWS Step FunctionsJSON state machine (Amazon States Language)Serverless glue on AWSManagedPer-transition cost. Standard workflows run up to 1 year
Argo WorkflowsDAG of Kubernetes podsCI/CD, ML training on KubernetesKubernetes CRDsPod startup overhead per step
Choreography (events only)No central orchestratorLoosely coupled, simple flowsSpread across servicesHard to see or change end-to-end flow

Operational concerns

  • Versioning: changing workflow code while old executions are in flight breaks replay. Use Temporal's patching or versioning APIs, or run old and new side by side.
  • Continue-as-new for long-lived workflows (subscriptions, polling), so history does not grow without bound.
  • Compensation is not rollback: a refund is a new transaction that may itself fail, so compensations need retries and alerting too.

Who uses it

  • Uber built Cadence, and Temporal is its fork by the original authors. Stripe, Netflix, Snap and Coinbase use Temporal for payments, infrastructure and CI workflows.
  • Airbnb created Airflow for data pipelines. It is now an Apache project.
Check yourself Question 1 of 3
No clock in workflows recall
From: Under the Hood: Deterministic Workflow Replay

Why must Temporal workflow code not call the system clock directly, for example to decide whether a deadline has passed?

Key Takeaways

DAG engines model complex multi-step workflows with strict dependency ordering and automatic retries.
Temporal uses event sourcing to recover state by deterministically replaying history logs without re-executing completed tasks.
The Saga pattern executes compensating transactions in reverse order when any intermediate workflow step fails.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue