Durable Agents with Restate

A one-module sample course on durable execution for AI agents with Restate. You kill a running agent on purpose, read the journal Restate kept, and count the model calls the replay paid for. Then you watch the same bug turn into a journal mismatch (RT0016), fix the replay with one line, and kill the fixed agent mid-call to find the window that line cannot close. Every number on these pages comes from a recorded run.

1 module~1.5 hours total

About This Course

An agent is a loop that asks a model what to do, does it, and asks again. Kill the process in the middle and something has to remember how far it got. Restate keeps a journal of each invocation: the input, every durable step and its result, every timer. When the process comes back, Restate replays the handler against that journal, skipping the steps it already has.

Restate can only replay what went through its context. A model call made with a plain HTTP request never reaches the journal, so the replay runs it again, and you pay for it again. If the model answers differently on replay, the handler diverges from the recorded journal and that attempt fails with a journal mismatch (RT0016). Restate retries it under the handler's retry policy: a later attempt may take the recorded path and complete, or the retries run out and the invocation pauses. This module shows all of that on a real Restate server, with the call counts, the journals and the error text, and ends on the rule that prevents it and the window a journaled call still leaves open.

The lab runs locally: a Restate server in Docker, a small Python agent, and a stub standing in for the model so every call can be counted.

Course design original to SciMigo. Pages link to and paraphrase Restate's documentation (docs.restate.dev and restate.dev, as fetched 2026-09-16); no documentation text is reproduced. Every observed number comes from SciMigo's demo repository, run against restate-server 1.7.10 with restate-sdk 1.0.5. Restate is developed by Restate GmbH; this course is independent and not endorsed by Restate.

Prerequisites

  • Comfortable Python, including async/await basics
  • Docker installed locally; no prior Restate

What You Will Learn

  • Explain what Restate's journal records for an invocation, and what a replay re-runs after the process dies
  • Predict the extra model calls a crash costs with and without ctx.run, and verify the count, including the call a journaled agent still repeats when it dies mid-call
  • Recognize a journal mismatch (RT0016) as replayed code diverging from the recorded journal, and trace how an unrecorded model decision causes it
  • Choose how to get a stuck invocation out: resume it on a journal-compatible fix, or kill it and restart it as new

Terminology Mapping

How classic concepts map to the terminology used in this course.

ClassicThis Course (Python)
Invocationone call of a handler, e.g. POST /WeatherAgent/run/send; has an invocation id (inv_…)
Durable stepawait ctx.run_typed("call model", ask_model, messages=messages)
Durable timerawait ctx.sleep(timedelta(seconds=6), name="rate-limit pause")
Journalthe sys_journal table (admin API /query) or the Restate UI's invocation timeline
Deterministic helpersctx.random(), ctx.uuid(), await ctx.time()
Invocation retry policyrestate.Service(..., invocation_retry_policy=InvocationRetryPolicy(max_attempts=20, on_max_attempts="pause"))

Your Learning Path

One self-contained module, about 90 minutes, to work through from top to bottom.

1

The Model Call You Pay For TwiceWhat Restate's journal keeps across a crash, what a replay re-runs, and why RT0016 is the same bug

A weather agent on Restate is killed in the middle of a durable pause. When it comes back, Restate replays the journal: the tool result is recorded, but a model call made outside ctx.run is not, so the replay pays for it again. Let the model answer differently and the replay fails with RT0016; let it stay different and every retry pays again until the invocation pauses. One line — ctx.run_typed around the model call — fixes the replay bug behind all three. The last experiment kills the fixed agent mid-call and finds the window that line cannot close: until Restate records a result, the call can run again.

90 minVideo lectureReading materialLab exercises