{"slug": "a-durable-google-adk-agent-needs-something-to-notice-the-crash", "title": "A Durable Google ADK Agent Needs Something to Notice the Crash", "summary": "A developer argues that Google ADK's event-history resumability still leaves a gap: nothing inside the framework detects a crashed run, so a caller must notice the failure and re-invoke with the original invocation_id, and multiple replicas have no coordination to prevent two runners claiming the same task. The proposed fix wraps ADK agents in a Dapr workflow runner (pip install \"diagrid[adk]\"), executing each tool call as a durable workflow activity so a failed process is reactivated on a healthy replica and resumes from the last completed activity, with a single workflow instance ID enforcing one owner per run.", "body_md": "Google ADK goes further on durability than most agent frameworks. Every interaction – user message, LLM response, tool call, tool result, state change – is recorded as an immutable Event. Turn on `ResumabilityConfig(is_resumable=True)`, re-invoke with the original `invocation_id`, and completed tool results come back from the event history. Only the tool that failed runs again.\n\nThe gap is in who starts that replay.\n\nFour minutes in, then a pod eviction\n\nAn ADK agent is four minutes into a three-tool task. Two tools have finished and their results are in the event history. The third has started. Then the pod gets evicted, and when it comes back, nothing happens.\n\nNothing inside ADK notices the crash. From outside, an agent that finished, an agent waiting on a slow tool and an agent whose process was killed look the same. The caller has to work out which one it's looking at and re-invoke with the right ID. If you run several replicas, there's a second problem: ADK has no coordination layer across them, so without external locking two runners can pick up the same task.\n\nWhat a durable ADK agent needs\n\nI'd list three things. A record of completed steps, which ADK already has. Something that notices a dead run and restarts it without a person or a cron job doing the detecting. And exactly one worker owning each run at a time.\n\nThe last two are runtime jobs. You can build them next to ADK – a watcher, a lock, a re-invoke path – or run the agent on something that already does them.\n\nMoving recovery into the runtime\n\n```\npip install \"diagrid[adk]\"\ndapr init\npython\nfrom google.adk.agents import LlmAgent\nfrom google.adk.tools import FunctionTool\nfrom diagrid.agent.adk import DaprWorkflowAgentRunner\n\ndef book_venue(city: str) -> str:\n    return f\"Venue held in {city}\"\n\ndef order_catering(headcount: int) -> str:\n    return f\"Catering ordered for {headcount}\"\n\ndef send_invites(city: str) -> str:\n    return f\"Invites sent for {city}\"\n\nagent = LlmAgent(\n    name=\"event_planner\",\n    model=\"gemini-2.5-flash\",\n    tools=[FunctionTool(book_venue), FunctionTool(order_catering), FunctionTool(send_invites)],\n    instruction=\"Plan an event by calling the three tools in sequence.\",\n)\n\nrunner = DaprWorkflowAgentRunner(name=\"event-planner\", agent=agent, max_iterations=10)\nrunner.start()\nout = runner.run_sync(user_message=\"Plan a 40-person meetup in Copenhagen\", session_id=\"cph-meetup\")\nprint(out.final_response)\nrunner.shutdown()\n```\n\nRun it with `dapr run --app-id event-planner -- python planner.py`. The agent definition is plain ADK, so it moves over unchanged.\n\nEach tool call now executes as a Dapr workflow activity, and the workflow log stores the activity's input, output and status, separately from ADK's event history. If the process dies, a durable reminder fires because the activity didn't complete, the workflow reactivates on a healthy replica, and it resumes from the last completed activity. Recovery goes through the workflow log instead of ADK's invocation_id replay path, so no caller has to detect anything or remember an ID.\n\nA workflow instance also has a single ID and runs in one place at a time, which takes care of two replicas grabbing the same task.\n\nWhere I'd start\n\nPick the ADK agent with the longest runs, since it has the most finished work to lose, and check who re-invokes it today when a pod goes away. If nobody does, that agent is the first one to wrap. The Google ADK page goes through recovery in more detail: [https://www.diagrid.io/learn/google-adk-durable-execution](https://www.diagrid.io/learn/google-adk-durable-execution)", "url": "https://wpnews.pro/news/a-durable-google-adk-agent-needs-something-to-notice-the-crash", "canonical_source": "https://dev.to/casper_nielsen_47eb2e6023/a-durable-google-adk-agent-needs-something-to-notice-the-crash-5602", "published_at": "2026-11-03 18:10:22+00:00", "updated_at": "2026-11-03 18:25:29.295567+00:00", "lang": "en", "topics": ["ai-agents", "ai-infrastructure", "developer-tools", "mlops"], "entities": ["Google ADK", "Dapr", "Diagrid", "Gemini 2.5 Flash", "DaprWorkflowAgentRunner"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/a-durable-google-adk-agent-needs-something-to-notice-the-crash", "markdown": "https://wpnews.pro/news/a-durable-google-adk-agent-needs-something-to-notice-the-crash.md", "text": "https://wpnews.pro/news/a-durable-google-adk-agent-needs-something-to-notice-the-crash.txt", "jsonld": "https://wpnews.pro/news/a-durable-google-adk-agent-needs-something-to-notice-the-crash.jsonld"}}