REALIADADTECH / BUILD & LEARN
← The flagship programme

MODULE 04 OF 12 · RELEASE 1

State, Memory & Durable Execution

Work that remembers where it got to, even if the power goes out mid-task.

You are following a recipe with twelve steps. Halfway through, the phone rings and you leave the kitchen for an hour. When you come back, you look at the pan and the ticked-off steps and carry on. You do not start again from the shopping.

So what is this really about?

Long jobs in software need the same thing: a written note of what has already been done. If the program restarts — a crash, a deploy, a server moving — it should read the note and carry on, not start over. Starting over is not just slow; if step two sent an email, starting over sends it twice.

A run that records each completed stepEach step records its result before the next begins, so a restart resumes at the next unfinished step rather than repeating work.Step 1Step 2Step 3Step 4done and written downrestart resumes here
Each step records its result before the next begins, so a restart resumes at the next unfinished step rather than repeating work.

QUICK CHECK

A four-step job crashes after step two. Step two sent a confirmation email. What must resuming NOT do?

The words you will hear

State
The ticked-off steps. What has happened so far, written down where it survives a restart.
Durable
Survives the program stopping. In a database, not in memory.
Resume
Picking up at step seven instead of step one.
Memory (conversation)
What was said earlier in a chat. Useful context — but not the official record of what was done.

By the end you will be able to

Going deeper

Why in-memory work disappears

A long job written the obvious way holds everything in variables: which step it is on, what each step produced, what to do next. The call stack is the plan.

That works right up until the process stops. And processes stop constantly for entirely routine reasons — you deployed, the platform moved your container, a memory limit was hit, someone restarted something. None of these is an emergency. All of them lose every job that was in flight.

The fix is not to prevent restarts. It is to make them uninteresting.

Write the plan down

Instead of holding the job in memory, keep a row that describes it:

{
  id,
  task,              // what we are doing
  step,              // which step we are on
  results,           // what each finished step produced
  state,             // running | waiting | done | failed
  updated_at,
}

Now a restart is a read. Load the row, look at step, carry on. Nothing is inferred from memory because nothing important was in memory.

This also makes the job inspectable while it is running, which is worth as much as the recovery. You can answer "where is this one stuck?" with a query rather than by adding logging and waiting for it to happen again.

Record before you act, not after

This is the rule the whole module turns on, and it is easy to get backwards.

The wrong order: do the thing, then record that you did it. If the process dies in between, the thing happened and nothing knows. Resuming does it again — a second email, a second charge, a second order.

The right order for anything irreversible: record that you are about to do it, do it, then record that it finished. A crash in the middle leaves a record saying "this was started and we do not know if it completed", which is awkward but honest — and far better than silently doing it twice.

For steps that only touch your own database, you can be simpler: do the work and the state update in one transaction, so either both happen or neither does.

Resuming is not replaying

There is a tempting alternative: instead of recording each result, just run the job from the start again and skip the steps that already happened.

It falls apart quickly. Skipping requires knowing what happened, which requires the record you were trying to avoid. And any step involving a model produces a different answer on the second run, so "replay" quietly becomes "do something different", which is worse than either alternative.

Store the result of each step. Resuming reads results; it does not recompute them.

Two kinds of memory, and why mixing them hurts

"Memory" in an agent usually means one of two very different things, and treating them as one causes real bugs.

Workflow state is what has happened: steps completed, results produced, actions taken. It is the source of truth. It must be exact, and it must never be summarised or dropped.

Conversation memory is what was said: the exchange so far, used to give the model context. It is helpful, it is inherently lossy, and it has to be bounded because conversations grow forever while context windows do not.

The bug that comes from conflating them: a system summarises old conversation turns to save space, and the summary quietly drops the fact that a refund was issued. Now the model believes no refund happened. If the refund had been workflow state, it would still be exactly recorded, because workflow state is never summarised.

Keep them in separate places with separate rules. Conversation memory needs a stated eviction policy — a turn limit, a token budget, a summarisation point — decided deliberately rather than discovered when a context window overflows in production.

Stopping properly

Every run needs a way to end that is not success. A step that has failed five times should move to failed and stay there, with the reason attached.

Without a terminal failure state, a job that cannot succeed retries forever: burning money, filling logs, and hiding the actual problem inside noise. A run that has given up and said why is far more useful than one still optimistically trying.

What good looks like

You can kill the process at any point during a job and restart it, and the job finishes correctly without repeating anything a customer would notice. You can query where any run has got to. And conversation memory has a size limit you chose, rather than one you will discover.

How it is put together

A run record holds the task, its current step, and the result of every completed step. Each step is a pure function of that state plus its own side effect, recorded before the step advances. Resuming means reading the record and continuing, not replaying. Conversation memory is a separate, size-bounded store — it informs prompts and is never the source of truth for what has happened.

Where you start

A three-step agent flow held entirely in memory, which loses everything if the process restarts.

The lab

  1. Model the flow as a run record with an explicit step and a result per step.
  2. Record each side effect before advancing, so a crash cannot lose it.
  3. Add resume: given a run id, continue from the recorded step.
  4. Add a bounded conversation memory with an explicit eviction rule.
  5. Add a terminal failure state that stops the run rather than looping.

What goes wrong, on purpose

The scenario. The process is restarted between step two and step three.

What should happen. Resuming continues at step three. Steps one and two are not repeated, and their side effects occurred exactly once.

How you prove it works

What you walk away with

An agent flow you can kill at any point and restart without duplicate effects, and a memory store with a stated eviction policy.