The event history is the source of truth

Instead of storing current variables, the engine appends every step's result to a durable event history on disk, so a crash that wipes RAM leaves the record of what already happened fully intact.

Previously

The double-charge came from trusting RAM; the fix is to append every step's result to a durable history that a crash can't wipe. But a saved record is useless on its own — we still need to get the half-finished ORDER #1001 back into the exact state it was in. How does the engine turn a log of events back into a running function?

Scene 02

The event history is the source of truth

  1. Watch
  2. Try it
  3. Predict
  4. Capture
WHAT WE STOREvariables in RAMappend-only historyIN-RAM VARIABLES · ORDER #1001state lives here → gone on crashcharged= truestep= 2EVENT HISTORY (APPEND-ONLY) · ON DISK · ORDER #1001SURVIVING STATE AFTER CRASHrunning…EVENT SOURCINGfold the log → current stateA bank ledger versus a sticky-note balance: the crash erases the note, never the ledger.
What to watch for

Scene 1's bug was that ORDER #1001's progress lived only in RAM, so the crash erased it. Watch the fix. As each step finishes, the engine writes one fact to a brand-new strip on disk: not a variable it can overwrite, but an event APPENDED to the end — WorkflowStarted, then ChargeCard scheduled, then ChargeCard completed=ok $42. The top RAM panel still mirrors the same progress as ordinary variables. That bottom strip is the event history: a durable, append-only log on disk that is only ever added to, never overwritten. Now drop the same crash. The RAM panel blanks exactly like before — but the event history is untouched. The lost sticky note vs the bank ledger: the record that ChargeCard already ran survives.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

Engine.recordStep
each finished step APPENDS one event — never overwrites
def recordStep(activity, result):
event = ActivityCompleted(activity, result)
history.append(event) # to disk, append-only
# the RAM cache is a convenience, not the truth
ram[activity] = result
return event
Engine.currentState
where are we now — derived, never stored
def currentState():
state = {}
for event in history.readFromStart():
state = apply(state, event) # fold left-to-right
return state # rebuilt, not saved
Engine.afterCrash
what survives under each store
def afterCrash():
ram = {} # RAM is wiped
if store == 'ram-variables':
return ram # nothing survived
# event sourcing: re-derive from the durable log
return currentState() # ChargeCard completed=ok

Where this sits in Build a workflow engine (Temporal / Airflow / Cadence style)

Scene 02 of 13, in the Durability act — Why RAM double-charges; the event history.. Stop trusting RAM: append every step's result to a durable, append-only event history, so a crash that wipes memory leaves the record of what already happened intact.

Up next. We have a durable record of what happened, but a record isn't a running program. To resume ORDER #1001 at step 2, the engine re-runs your code from the top and feeds it the recorded results instead of re-doing them — a move called replay.

All 13 scenes in Build a workflow engine (Temporal / Airflow / Cadence style) · Every curriculum

Built with Arqly
Every scene in Build a workflow engine (Temporal / Airflow / Cadence style) builds on the one before it.All 13 Build a workflow engine (Temporal / Airflow / Cadence style) scenes