Quickstart: Crash Recovery
Run a durable Spring AI booking agent, kill it mid-call, and recover the same run by re-issuing the request under an instance id you own — so a retry attaches to the in-flight workflow instead of starting a second booking.
You will learn how to:
- Schedule a durable
ChatClient.call()under a caller-owned instance id (DurableAdvisor.INSTANCE_ID_KEY) - Survive a hard crash of the app (which also hosts the in-process workflow worker)
- Re-attach to the resumed run on restart and collect its result — with no duplicate side effect
- Make a real, side-effecting tool safe to retry
Prerequisites
- Diagrid Catalyst account
- Diagrid CLI
- JDK 21 or later, and Maven 3.9+
- An OpenAI API key
1. Log in to Catalyst
diagrid login
diagrid whoami
2. Clone and Navigate
git clone https://github.com/diagridio/catalyst-quickstarts.git
cd catalyst-quickstarts/agents/spring-ai/crash-recovery
3. Explore the Code
The booking agent is a named ChatClient bean so its run gets a per-agent workflow name. Each call
sets a caller-owned instance id via DurableAdvisor.INSTANCE_ID_KEY — that id is the attach handle a
retry re-uses:
@GetMapping("/crash/book")
public ResponseEntity<String> book(@RequestParam String id,
@RequestParam(defaultValue = "ABC123") String reference) {
try {
String answer = agent.prompt()
.user("Confirm the booking with reference " + reference + ".")
.advisors(a -> a.param(DurableAdvisor.INSTANCE_ID_KEY, id)) // caller-owned id → attach on retry
.call()
.content();
return ResponseEntity.ok(answer);
} catch (DurableCallTimeoutException e) {
// Wait budget elapsed (not a failure): the run is still going — re-issue the same id to attach.
return ResponseEntity.accepted().body("still running as " + e.instanceId() + " — re-issue to attach");
}
}
The booking tool is a global @Tool bean (SlowBookingTools.commitReservation) that sleeps ~30s —
long enough to crash mid-call. It must be a bean (not a per-call tool) so it's re-registered on the
restarted worker and the resumed activity can run it. Its confirmation code is derived from the
reference, so a re-attached call returns the same code — visible proof the booking wasn't redone.
4. Configure API Key
- macOS/Linux
- Windows
export OPENAI_API_KEY="your-openai-api-key"
$env:OPENAI_API_KEY="your-openai-api-key"
5. Install Dependencies
mvn package -DskipTests
6. Run with Catalyst Cloud
Create the Catalyst project with agent infrastructure enabled (and set it as the default for this session), register the agent, then run:
diagrid project create spring-ai-crash-recovery --enable-agent-infrastructure --wait --use
diagrid agent create spring-ai-crash-recovery --wait
diagrid dev run -f dev-spring-ai-crash-recovery.yaml --approve
7. Crash and re-attach
7.1 Book under an id you own (blocks ~30s)
From Terminal A — this schedules the booking under trip-42 and blocks while the tool "commits":
curl "http://localhost:8080/crash/book?id=trip-42&reference=ABC123"
Watch the app log for >>> commitReservation(ABC123) — committing over ~30s.
7.2 Kill the app mid-call
From Terminal B, during that window:
curl -X POST "http://localhost:8080/crash/kill"
The app process dies (Terminal A's curl sees a reset). The workflow trip-42 keeps living in Catalyst.
7.3 Restart the app
The project and agent already exist, so just run:
diagrid dev run -f dev-spring-ai-crash-recovery.yaml --approve
The durable runtime resumes instance trip-42; the pre-crash LLM turn is not re-executed.
7.4 Re-issue the same call — it attaches
From Terminal A, re-run the exact same request:
curl "http://localhost:8080/crash/book?id=trip-42&reference=ABC123"
It attaches to the resumed run (waiting if it's still committing, or returning the recorded answer if it finished) and returns the same confirmation code — no second booking:
Booking ABC123 confirmed. Confirmation code: BK-...
The instance id is a bearer handle you own — guard it like a primary key. A durable activity is at-least-once, so a side-effecting tool should key off a business value (here, the booking reference) to stay idempotent under recovery.
8. View in the Catalyst Web Console
Open the Catalyst Cloud web console, go to Workflows, and inspect
instance trip-42 — the completed activity was not re-executed on recovery.
9. Clean Up
Stop the app with Ctrl+C, then delete the project:
diagrid project delete spring-ai-crash-recovery
Summary
In this quickstart, you:
- Scheduled a durable
ChatClient.call()under a caller-owned instance id - Killed the app mid-booking and saw the workflow survive in Catalyst
- Re-attached on restart by re-issuing the same id — same confirmation code, no double booking
- Made a side-effecting tool safe to retry
Next Steps
- See the durable memory quickstart for how the synchronous advisor chain interacts with durability
- Learn more about Spring AI + Dapr
- Learn how to deploy AI agents to Kubernetes
Spring is a trademark of Broadcom Inc. and/or its subsidiaries.