Learn / Practice

Durable Java turns: what survives a process crash?

AI-APPS / BUILD · Engineering cases

Checksummed append records, 142 truncated prefixes and three halted JVMs distinguish local recovery from remote exactly-once execution.

INTERMEDIATE · 9 MIN · UPDATED 2026-10-07 · PART 13 / 17

What was published after this article?

The original conclusions and next-step proposals are retained. These published follow-ups do not imply that every limitation has been resolved.

KEEP EXPLORING

Related content

  1. Tutorials

    Java idempotent retries: no reply does not mean no effect

    Seven loopback HTTP fault cases explain idempotency keys, concurrent admission, payload conflicts and process-crash gaps.

    11 MINPublished

View count unavailable

On this page 5

Pinned code · Raw evidence · Lab record

Atomic in-memory turns disappear when the process exits. Replacing one large JSON file can leave the entire file unreadable after a partial write. TurnJournal appends one validated question/answer pair per checksummed record and gives partial tails a specific recovery rule.

Commit order

JSON {id, question, answer}
→ UTF-8 → Base64(payload) + space + SHA256(payload) + newline
→ write every byte → FileChannel.force(true)
→ update in-memory history → acknowledge

Base64 keeps embedded newlines out of the record delimiter, at the cost of larger files. The checksum detects accidental corruption; it is not authentication against someone who can edit the file and recompute it. The Java8 FileChannel contract also depends on storage type. Power loss and network filesystems were not tested.

Recovery, not silent data deletion

Complete lines must pass format, checksum and duplicate-ID checks. An incomplete trailing line is truncated back to the last complete record. A corrupted complete line rejects the journal instead of skipping missing history. The teaching log is capped at 4MiB and an exclusive FileLock rejects a second writer. Use it synchronously from one owning thread; it is not a database isolation implementation.

Actual child-process halt Recovered turns Meaning
Before writing the second turn 1 No new commit
Halfway through its record 1 Incomplete tail removed
After commit and force 2 Complete turn recovered

Each child JVM exits via Runtime.halt(23), then another JVM reopens the journal. The suite also checks all 142 incomplete byte prefixes of the second record and rejects a separate corrupted complete record.

Local deduplication has a boundary

Committing the same ID and question again returns the original answer. Reusing that ID for a different question fails. Checking find(id) before a remote request can reuse an already committed answer.

However, the remote provider may finish before the process crashes and before the local journal is committed. A missing local record does not prove no remote work occurred. Without a transactional provider or real remote idempotency, this journal cannot guarantee exactly-once model invocation.

Inspect the artifacts

before.log and partial.log recover one turn; committed.log recovers two. crashes.json records the exits. turns.log is intentionally corrupted by the negative case and is not a healthy example.

In a disposable copy, alter a Base64 character without updating its checksum: opening should fail. Truncate only the final line: earlier complete turns should survive. An “already open” error calls for checking another writer, not clearing the file. After a write error, end use of that instance and reopen for recovery rather than appending past a possible partial write.

The three components suggest a pipeline: load committed turns, select bounded context, execute with a budget, validate the response, then commit the whole turn. This batch delivers tested components, not an online production assistant or a remote model-quality result.

Reproduce from a clean checkout

Java 8, Python 3 and Gson 2.10.1. Replace the two paths with your local JDK and jar.

git clone https://github.com/VirtualSelect/hohoo-ai-lab.git hohoo-ai-lab-study
cd hohoo-ai-lab-study
git checkout 02a2660e22c969e70e3a6f095003614a7dfa448e
python demos/11-bounded-assistant/run.py --java-home /path/to/jdk8 --gson /path/to/gson-2.10.1.jar --out outputs/my-run
python demos/11-bounded-assistant/audit.py outputs/my-run

Use a new output directory. Windows was exercised; Linux/macOS were not rerun. No model API or key is required. The source commit in the manifest precedes the evidence commit linked above; source hashes bind the executed files.

A note to your future selfBefore you move on, keep one thought of your own.

Your private reading note stays in this browser; it is never uploaded or published. Clearing browser data removes it, so export a copy to keep. This article’s translations share the same note.

Next published article:Java idempotent retries: no reply does not mean no effect →

You are here

BUILD / AI Applications

  1. ○ Java retries: three timeouts are not one deadline
  2. ○ Durable Java turns: what survives a process crash?
  3. ○ Java idempotent retries: no reply does not mean no effect

KEEP EXPLORING

Related content

  1. LAB / 032

    Durable Java turns: what survives a process crash?

    Checksummed append records, 142 truncated prefixes and three halted JVMs distinguish local recovery from remote exactly-once execution.

    Completed
  2. PROJECT / 002

    Java LLM Practice

    Reproducible Java conversation, retry and persistence boundaries, alongside attention, cache-cost and quantization-error experiments.

    Building
  3. Engineering cases

    Java history and request windows: can a trimmed fact return?

    Follow narrowing, commit, restart and expansion to separate durable conversation history from one request context.

    9 MINPublished

Which way next?

Based on article relationships and published same-topic content, not random recommendations.

← All writing