Elena' s AI Blog

Production Hardening: Idempotency, Run Isolation, and Crash Safety

02 Aug 2026 (updated: 07 Sep 2026) / 28 minutes to read

Elena Daehnhardt

Generated by Midjourney. Prompt: A sealed black box representing opaque AI decision-making.


TL;DR:
  • Every run gets a stable job_id and thread_id, its own artifact folder, and atomic file writes, so two runs — or two crashes — can no longer corrupt each other's output.
  • A `finalized` flag guards against ordinary replay, but only an idempotency key in durable storage closes the crash window between a side effect and its checkpoint.
  • SQLite is a solid checkpointer for one host; PostgreSQL is the documented choice once you add concurrent workers or multiple replicas.

📚 This post is part of the "AI Orchestration" series

Series: AI Orchestration (Part 32 of 23)

Previous: Part 18 — DeepSeek R1 With Ollama

Production Hardening: Idempotency, Run Isolation, and Crash Safety

So far in this series, my system works. But production systems are not tested by success. They are tested by failure, and I would rather find that out on my own terminal than at 2am from a Slack message.

So let me ask my own setup some uncomfortable questions:

  • What if the container crashes mid-run?
  • What if Slack sends the same approval twice?
  • What if I click Approve twice by accident?
  • What if I restart Docker while the graph is sitting on an interrupt?
  • What if two runs share the same output folder?
  • What if the crash lands exactly between a side effect and the checkpoint that was supposed to record it?

Right now, my system might survive these by luck. After this post, it handles them deliberately — and I will be honest about where “deliberately” still has edges.


Stable Identity: Job, Run, and Thread Are Not the Same Thing

I started this hardening pass by hashing a snippet of the newsletter intro into a thread_id. It worked, right up until I thought about it properly:

import hashlib

def generate_thread_id(intro: str) -> str:
    base = intro[:50]
    digest = hashlib.sha256(base.encode()).hexdigest()[:8]
    return f"newsletter-{digest}"

Three problems, in ascending order of embarrassment. First, I only hash the first 50 characters, so two newsletters that happen to open with the same boilerplate greeting collide deterministically — not a hypothetical, just a matter of time. Second, eight hex characters is 32 bits of identifier space, which is thin for very little reason; there is no cost to using 16. Third, and the one that actually matters: identical content and identical execution are not the same concept. If I intentionally rerun a newsletter after tweaking the prompt, should that resume the old workflow, silently overwrite it, or start a fresh attempt? A thread_id built purely from content cannot answer that question, because it was never designed to.

So I split identity into three layers instead of one:

job_id      = identity of the logical newsletter (this Friday's issue)
run_id      = identity of one particular execution attempt
thread_id   = the LangGraph checkpoint stream for that execution
from datetime import date
import hashlib
import re

def slugify(value: str) -> str:
    value = value.lower().strip()
    return re.sub(r"[^a-z0-9]+", "-", value).strip("-")

def make_job_id(newsletter_date: date, title: str) -> str:
    return f"newsletter-{newsletter_date.isoformat()}-{slugify(title)}"

def make_thread_id(job_id: str, source_text: str, workflow_version: str) -> str:
    payload = "\0".join([job_id, source_text, workflow_version])
    digest = hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]
    return f"{job_id}-{digest}"

job_id is what I look up in logs and dashboards. thread_id is what the checkpointer actually keys on — and because it hashes the full source text plus a workflow version rather than the first 50 characters of an intro, a rerun after a prompt change gets a new, distinguishable thread instead of quietly colliding with the old one. If I want explicit reruns rather than content-derived ones, I append an attempt suffix: newsletter-2026-08-07-ai-signals-a1, -a2, and so on. LangGraph’s checkpointer uses the exact thread_id as its lookup key — lose it or collide it, and you lose the ability to resume that run at all, so this is not a place to be casual.


You've hit a Deep Dive tutorial.

I spend dozens of hours researching, coding, and breaking things to write these guides. This content is free, but reserved for my subscriber community. Drop your email below to unlock this guide (and all past/future deep dives):

Already a subscriber? Use the magic link from your last newsletter, or reset your password.

New subscribers get an inbox mail: Set a password to unlock articles. The form does not log you in — use the same email afterwards.

desktop bg dark

About Elena

Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.



Citation
Elena Daehnhardt. (2026) 'Production Hardening: Idempotency, Run Isolation, and Crash Safety', daehnhardt.com, 02 August 2026. Available at: https://daehnhardt.com/blog/2026/08/02/idempotency-run-isolation-and-crash-safety/
All Posts