Unit 07.00: Pausing a graph mid-run
A human review step is not a prompt asking the model to wait. It is the run genuinely stopping, with its state durable, until something restarts it.
interrupt_before, and a state that outlives the process
Compiling with interrupt_before names the nodes the graph must stop ahead of. The run reaches that point, writes a checkpoint, and returns.
The code pauses before publish and inspects what was saved.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
class State(TypedDict):
draft: str
published: bool
def write(state: State):
return {"draft": "the finished draft"}
def publish(state: State):
return {"published": True}
g = StateGraph(State)
g.add_node("write", write)
g.add_node("publish", publish)
g.add_edge(START, "write")
g.add_edge("write", "publish")
g.add_edge("publish", END)
app = g.compile(checkpointer=InMemorySaver(), interrupt_before=["publish"])
config = {"configurable": {"thread_id": "review-1"}}
app.invoke({"draft": "", "published": False}, config)
snapshot = app.get_state(config)
print("paused before:", snapshot.next)
print("state now :", snapshot.values)
# The run stops before `publish` and the state is durable. Nothing is holding a
# connection open, so the pause can last minutes or days -- which is what makes
# a human step practical rather than a timeout waiting to happen.
snapshot.next reports which node is pending - publish - and the state holds the finished draft. Nothing is blocking: no thread is parked, no connection is held open, no timeout is counting down.
That is what makes a human step practical. The pause can last four minutes or four days, survive a deploy, and be resumed by a different process entirely, because the only thing carrying the run forward is a row in the checkpoint store.
The mistake this prevents
The mistake is implementing review by blocking inside a node - polling a queue, or awaiting a webhook. It holds a worker for the duration, breaks at the first restart, and turns a review that takes a day into a timeout. Stop the run instead of waiting inside it.
Takeaway
interrupt_before stops the run and checkpoints it. Because nothing is held open, the pause can last as long as a human needs and survive restarts and deploys.
