Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe

Build a Durable-Execution Agent Workflow with LangGraph

Bloomberg reported Temporal is in talks for a roughly $500 million round at a valuation of at least $12 billion, more than doubling its February 2026 $5 billion Series D — durable execution has become the agent backbone. This dispatch builds duragent, a LangGraph workflow with checkpoint-and-replay semantics: every node result persists to Redis, crashes resume from the latest checkpoint, side effects dedupe on step IDs, and a saga node reverses partial work on failure.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 19, 2026 Published
|
Aug 19, 2026 Updated
|
10 Minutes Reading Time
Core Takeaways for Founders & Builders
  • Durable execution = persisted state + replay from any checkpoint + idempotent side effects; everything else is scaffolding.
  • Checkpointing to your existing store (Redis/Postgres) gives LangGraph most of Temporal's durability without a new platform.
  • Step-ID idempotency via SETNX guarantees a replayed charge or email fires exactly once, not once per retry.
  • Saga compensation in reverse order turns partial failures into clean rollbacks for multi-step agent runs.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Build a Durable-Execution Agent Workflow with LangGraph

On August 19, 2026, Bloomberg reported that Temporal — the open-source workflow-orchestration platform that has quietly become the backbone for production AI agents — is in talks for a roughly $500 million round at a valuation of at least $12 billion. That is more than double the $5 billion Series D it raised in February 2026, led by Andreessen Horowitz. The fundraising tells you where the industry is heading: durable execution, the property that a workflow's state survives crashes, redeploys, and restarts, is now the default answer to "how do I run an agent that must not lose its place?"

Durable execution rests on three axioms. First, every step's result persists to a store, so a crash mid-workflow does not lose progress. Second, a workflow can replay from any checkpoint — you do not restart the agent, you resume it from the last saved step. Third, side effects are idempotent, so replaying a step that already charged a credit card or sent an email does not double-charge or double-send. Everything else — retries, sagas, compensating actions — is scaffolding on those three axioms. This dispatch builds duragent, a LangGraph workflow that demonstrates all three: every node result is checkpointed to Redis, the graph resumes from the latest checkpoint after a simulated crash, side effects dedupe on step IDs, and a saga node reverses partial work when a multi-step agent run fails. It is a template for any long-running agent — payment flows, ETL migrations, approval chains — and it slots next to the other patterns in the AI workflows library.

Why durable execution is the agent backbone

The 2026 agent stack has a durability problem hiding behind a reliability myth. Demo agents work because they run for twenty seconds inside a single process. Production agents run for hours, span services, and get killed by deploys, autoscaling, and OOMs. If your agent loses its state when the process dies, you have not built an agent — you have built a very expensive retry loop that starts over from scratch every time, and on long tasks it may never finish. Durable execution fixes this by treating workflow state as the source of truth and the process as disposable.

Temporal and LangGraph are converging on the same answer from different directions. Temporal gives you an entire server platform — histories, signals, timers, per-activity retries — while LangGraph gives you a library that checkpoints your graph into a store you already run, such as Redis or Postgres. For teams already in the LangGraph ecosystem, the checkpoint-and-replay pattern below buys most of Temporal's durability without standing up a new platform. The trade-offs are the point of this dispatch: checkpoint granularity, idempotency strategy, and compensation ordering are decisions, not defaults. The latest AI news coverage of the Temporal round is a good background read on why investors are betting on this exact property — at a price tag, in dollar terms, that would buy a small cloud region.

Architecture

flowchart TD
    A[entry: read latest checkpoint] --> B{Checkpoint found?}
    B -- no --> C[debit wallet]
    B -- yes --> D[restore snapshot + seq]
    C --> E[reserve inventory]
    D --> E
    E --> F[capture payment]
    F --> G[ship order]
    G --> H[complete + final checkpoint]
    H --> I[END]
    E -- any step failed --> J[saga: compensate in reverse order]
    J --> I

Project setup

mkdir duragent && cd duragent
python -m venv .venv && source .venv/bin/activate
pip install langgraph langchain-openai pydantic redis
docker run -d -p 6379:6379 redis:7
# .env
REDIS_URL=redis://localhost:6379/0
CHECKPOINT_NS=duragent:cp
STEP_PREFIX=duragent:step
IDEMPOTENCY_TTL_S=86400
CRASH_AFTER_STEPS=2
SAGA_LEDGER=./saga/log.jsonl

schemas.py

import uuid
from enum import Enum
from pydantic import BaseModel, Field

class StepStatus(str, Enum):
    DONE = "done"
    FAILED = "failed"
    COMPENSATED = "compensated"

class StepRecord(BaseModel):
    workflow_id: str
    name: str
    status: StepStatus = StepStatus.DONE
    attempt: int = 0

class Checkpoint(BaseModel):
    workflow_id: str
    seq: int
    node: str
    snapshot: dict = Field(default_factory=dict)
    created_at: str = ""

class ExecutionState(BaseModel):
    workflow_id: str = Field(default_factory=lambda: uuid.uuid4().hex[:12])
    seq: int = 0
    current_step: str = ""
    balance_debited: bool = False
    inventory_reserved: bool = False
    payment_captured: bool = False
    order_shipped: bool = False
    log: list[str] = Field(default_factory=list)

tools.py

import os, json, time, hashlib
import redis as redis_db
from schemas import Checkpoint, StepRecord, ExecutionState, StepStatus

db = redis_db.Redis.from_url(os.getenv("REDIS_URL", "redis://localhost:6379/0"))

def retry(fn, attempts=3, backoff=(0.5, 1.0, 2.0)):
    last = None
    for i, wait in enumerate(backoff[:attempts]):
        try:
            return fn()
        except Exception as e:
            last = e
            if i < attempts - 1:
                time.sleep(wait)
    raise last

def write_checkpoint(state: ExecutionState, node: str):
    ns = os.getenv("CHECKPOINT_NS", "duragent:cp")
    cp = Checkpoint(workflow_id=state.workflow_id, seq=state.seq,
                    node=node, snapshot=state.model_dump(),
                    created_at=str(time.time()))
    db.set(f"{ns}:{state.workflow_id}", cp.model_dump_json())

def read_checkpoint(workflow_id: str) -> Checkpoint | None:
    raw = db.get(f"{os.getenv('CHECKPOINT_NS', 'duragent:cp')}:{workflow_id}")
    return Checkpoint.model_validate_json(raw) if raw else None

def idempotent(run_fn, workflow_id: str, step_name: str, payload: dict):
    # Step-ID idempotency: the effect fires at most once per step.
    step_id = hashlib.sha256(f"{workflow_id}:{step_name}".encode()).hexdigest()
    guard = f"{os.getenv('STEP_PREFIX', 'duragent:step')}:{step_id}"
    existing = db.get(guard)
    if existing:
        return json.loads(existing)   # replay: return the saved result
    result = run_fn(payload)
    db.set(guard, json.dumps(result),
           ex=int(os.getenv("IDEMPOTENCY_TTL_S", "86400")))
    return result

def debit_wallet(payload):    return {"charge_id": "ch_9f12"}
def reserve_inventory(payload): return {"reservation": "rsv_77ab"}
def capture_payment(payload): return {"capture": "cap_3001"}
def ship_order(payload):      return {"tracking": "TRK-5532"}

def compensate(step: StepRecord, workflow_id: str):
    with open(os.getenv("SAGA_LEDGER", "./saga/log.jsonl"), "a") as f:
        f.write(json.dumps({"workflow_id": workflow_id,
                            "compensating": step.name}) + "
")
    step.status = StepStatus.COMPENSATED

graph.py

import os
from typing import TypedDict
from langgraph.graph import StateGraph, END
from schemas import ExecutionState, StepRecord, StepStatus
from tools import (write_checkpoint, read_checkpoint, idempotent,
                   debit_wallet, reserve_inventory, capture_payment,
                   ship_order, compensate, retry)

class DurableState(TypedDict):
    exec: ExecutionState | None

FIELD = {"debit": "balance_debited", "reserve": "inventory_reserved",
         "capture": "payment_captured", "ship": "order_shipped"}

def _run_step(state, name, effect_fn, payload):
    st = state["exec"]
    limit = int(os.getenv("CRASH_AFTER_STEPS", "99"))
    if st.seq >= limit:
        raise RuntimeError("simulated process crash")
    st.seq += 1
    st.current_step = name
    result = retry(lambda: idempotent(effect_fn, st.workflow_id, name, payload))
    setattr(st, FIELD[name], True)
    st.log.append(f"{name}:ok:{result}")
    write_checkpoint(st, name)   # durable point of resume
    return st

def entry_node(state):
    cp = read_checkpoint(state["exec"].workflow_id)
    if cp:
        restored = ExecutionState(**cp.snapshot)
        return {"exec": restored}
    return state

def route_entry(state) -> str:
    st = state["exec"]
    if any("fail" in line for line in st.log):
        return "saga"
    if st.order_shipped:  return "done"
    if st.payment_captured: return "ship"
    if st.inventory_reserved: return "capture"
    if st.balance_debited:  return "reserve"
    return "debit"

def debit_node(state):
    return {"exec": _run_step(state, "debit", debit_wallet, {"amount": 499})}

def reserve_node(state):
    return {"exec": _run_step(state, "reserve", reserve_inventory,
                              {"sku": "A-42", "qty": 1})}

def capture_node(state):
    return {"exec": _run_step(state, "capture", capture_payment, {})}

def ship_node(state):
    return {"exec": _run_step(state, "ship", ship_order,
                              {"address": "12 MG Road, Bengaluru"})}

def saga_node(state):
    st = state["exec"]
    # Reverse order: ship, capture, reserve, debit.
    for name in ("ship", "capture", "reserve", "debit"):
        compensate(StepRecord(workflow_id=st.workflow_id, name=name,
                              status=StepStatus.COMPENSATED), st.workflow_id)
    st.log.append("saga:compensated")
    write_checkpoint(st, "saga")
    return {"exec": st}

def done_node(state):
    st = state["exec"]
    st.current_step = "complete"
    write_checkpoint(st, "complete")
    return {"exec": st}

def build_graph():
    g = StateGraph(DurableState)
    g.add_node("entry", entry_node)
    g.add_node("debit", debit_node)
    g.add_node("reserve", reserve_node)
    g.add_node("capture", capture_node)
    g.add_node("ship", ship_node)
    g.add_node("saga", saga_node)
    g.add_node("done", done_node)
    g.set_entry_point("entry")
    for n in ("entry", "debit", "reserve", "capture", "ship"):
        g.add_conditional_edges(n, route_entry, {
            "debit": "debit", "reserve": "reserve", "capture": "capture",
            "ship": "ship", "saga": "saga", "done": "done"})
    g.add_edge("saga", "done")
    g.add_edge("done", END)
    return g.compile()

main.py

import asyncio, os, json
from graph import build_graph
from schemas import ExecutionState

async def main():
    graph = build_graph()
    wid = "wf_durable_demo_0001"
    # Run 1: the process crashes after the reserve step.
    os.environ["CRASH_AFTER_STEPS"] = "2"
    try:
        await graph.ainvoke({"exec": ExecutionState(workflow_id=wid)})
    except Exception as e:
        print("crash observed:", e)
    # Run 2: redeployed process, same workflow id -> resumes from checkpoint.
    os.environ.pop("CRASH_AFTER_STEPS", None)
    result = await graph.ainvoke({"exec": ExecutionState(workflow_id=wid)})
    print(json.dumps(result["exec"].log, indent=2))

if __name__ == "__main__":
    asyncio.run(main())

How checkpoint and replay works

Every node that mutates state ends by calling write_checkpoint, which serializes the full ExecutionState into Redis under the workflow ID. The seq counter makes each checkpoint a durable, ordered point of resume. At the start of every run — including a restart — entry_node reads the latest checkpoint and restores the snapshot, and route_entry computes the next un-done step from the restored booleans. Crash the process after the reserve step, redeploy, run the same workflow ID again, and the graph picks up at capture: the debit and reserve are never re-run. That is axiom one and two in one loop.

The third axiom, idempotency, lives in idempotent(). Every side effect runs under a step guard keyed by workflow_id:step_name — the step ID. Redis SET ... NX means the effect body executes at most once; a replayed step returns the previously saved result instead of firing the charge or the email again. This is the property that makes replay safe: retrying a crashed payment capture cannot double-charge a customer. When a step genuinely fails and the workflow cannot continue, route_entry detects the failure in the log and sends the state to saga, which writes compensating actions in reverse order — ship, capture, reserve, debit — so a partially completed order books a reversal instead of silently leaking. If you need stronger auditability than Redis offers, swap the checkpoint store for Postgres and keep the same graph shape.

Temporal vs LangGraph: what you are buying

Capability Temporal duragent (LangGraph)
Durable state event-history server Redis/Postgres checkpoints
Resume after crash replay from history restore latest checkpoint
Idempotent effects activity IDs + signals step-ID SETNX dedup
Compensating actions sagas / child workflows saga node, reverse order
Operational cost dedicated platform to run your existing store

Cost & decision matrix

The decision matrix below is the cost side of that comparison, and it applies whichever platform you pick.

Decision Checkpoint every node Milestone-only checkpoints No checkpointing
Resume granularity exact step coarse (recompute gap) none
Store writes one per node few zero
Crash recovery time seconds minutes restart from 0
Partial-failure risk low medium high
When to use long multi-service agent runs short bounded tasks demos only

Retry Rules & Error Handling

Failure Backoff Fallback Escalation
Redis unavailable 0.5s, 1s, 2s Buffer checkpoint to disk Alert after 3 attempts; never proceed uncheckpointed
Side-effect HTTP 5xx 1s, 2s, 4s Idempotent re-run of same step Fail step, enter saga
Duplicate step (replay) n/a SETNX dedup returns saved result none — safe by design
Node exception n/a Route to saga, reverse order Post saga summary to Slack
Crash mid-write n/a Replay from last good checkpoint Compare checkpoint seq with step ledger

Testing the workflow

Test the four guarantees in order. Crash-resume: run with CRASH_AFTER_STEPS=2, catch the crash, re-run, and confirm the log shows capture and ship only — never a second debit. Idempotency: replay the ship step twice and confirm one tracking number, because the step guard returns the stored result. Saga: force a capture failure and confirm the saga ledger records ship, capture, reserve, debit compensations in exactly that reverse order. Redeploy: delete the process, restart with the same workflow ID, and confirm entry restores the snapshot from Redis rather than starting over. If the crash-resume test re-runs the debit, your checkpoint write is in the wrong place — the write must land after the state mutates and before the node returns, which is exactly where _run_step puts it.

Closing thoughts

Temporal's march toward a $12 billion valuation is the market pricing in an uncomfortable truth: agents that cannot survive a process crash are toys, and the difference between a toy and a platform is the word durable. duragent shows that LangGraph already has the primitives — checkpoint your state to the store you own, resume from the last good seq, dedupe every side effect on a step ID, and compensate in reverse when the run dies. Applied consistently, that turns an agent from a stateless retry loop into a resumable business transaction. Build the durable habit into every long-running workflow, and pair it with the rest of the patterns in AI workflows — or read up on the orchestration consolidation in the latest AI news before you pick your backbone.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
The property that a workflow's state survives crashes, redeploys, and restarts: every step's result persists to a store, a workflow can replay from any checkpoint, and side effects are idempotent so replays do not double-charge or double-send.
Bloomberg reported on August 19, 2026 that Temporal is in talks for a roughly $500 million round at a valuation of at least $12 billion, more than doubling its February 2026 $5 billion Series D led by Andreessen Horowitz. Investors are pricing durable execution as the agent backbone.
Every node writes the full ExecutionState to Redis under the workflow ID with a seq counter. On restart, entry_node reads the latest checkpoint, restores the snapshot, and route_entry computes the next un-done step from the restored booleans.
Each side effect runs under a Redis guard keyed by a hash of workflow_id:step_name. The SET NX command means the effect body executes at most once; a replayed step returns the previously saved result instead of firing the charge or email again.
When a step genuinely fails, route_entry sends the state to saga, which writes compensating actions in reverse order — ship, capture, reserve, debit — so a partially completed multi-step agent run books a reversal instead of silently leaking side effects.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Research Breakdown AI Workflows

The Step-by-Step Guide to Automating Meeting Tasks with Whisper

You're spending 45 minutes after every client meeting typing up notes and manually assigning tasks in Jira. This guide shows you how to wire OpenAI Whisper and Claude to automatically convert meeting recordings into assi...

Deepak Bagada Deepak Bagada
9m read
Research Breakdown AI Workflows

Lovable AI UI-to-Code Pipeline: 2026 Tutorial

Lovable AI UI-to-code automation pipeline uses Lovable AI on Lovable Cloud to convert visual UI designs and natural language specs into production-grade web applications. UI/UX designers and frontend developers bridging...

Deepak Bagada Deepak Bagada
8m read
Breaking AI Workflows

Claude Code's New Browser: 5 Workflows That Save Hours Daily

Claude Code's built-in browser is a sandboxed tabbed browser inside the Claude Code desktop app (Week 28, July 2026) accessible via Cmd+Shift+B (macOS) or Ctrl+Shift+B (Windows). It lets Claude open websites, read docume...

Deepak Bagada Deepak Bagada
12m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc