Skip to content

Session Persistence

pawaca edited this page Aug 30, 2026 · 2 revisions

Session Persistence

Edge adaptation of the upstream session event persistence backend.

Upstream reference: Session documentation

What Upstream Provides

Upstream persists session events as append-only JSONL files — one file per session. The SessionPersistence interface defines the contract: materialize sessions, append event batches, list sessions, read history pages, commit crash-recovery repairs, and flush durability checkpoints. Events are lossless JSON with continuous sequence numbers.

What Edge Changed

Replacement JSONL → DO SQL

DurableObjectSessionPersistence implements the upstream SessionPersistence interface using five Durable Object SQL tables:

Table Purpose
dsh_session_persistence_state Schema version tracking
dsh_sessions Session headers (id, cwd, version, parent, origin, incarnation)
dsh_session_events Event log (session_id, seq, type, time, data as JSON text)
dsh_edge_blank_sessions Pre-published blank sessions awaiting first prompt
dsh_session_summaries Materialized session-list metadata

Replacement Chunk packing

Consecutive assistant/chunk, reasoning/chunk, and tool-call/chunk events are compressed into single storage rows (text-chunks, reasoning-chunks, tool-call-chunks) on write via packChunkRuns(). Decoded back to individual events on read via decodeStorageRecord(). Reduces DO SQL row count by 5–10× for long sessions.

Replacement Materialized summaries

dsh_session_summaries stores precomputed session-list metadata (updated_at, last_prompt_at, last_seq, blank, title). Updated atomically inside appendBatch()'s transaction. List operations read via SESSION_SUMMARY_MATERIALIZED — a single JOIN, no subqueries. The subquery-based SESSION_SUMMARY_SELECT exists only inside recomputeSummary() for boot-time stale-row repair.

What Edge Did NOT Change

  • SessionPersistence interface contract
  • Event format, sequence numbering, and append-only guarantee
  • Flush/checkpoint semantics
  • Crash-recovery repair via commitRepair()
  • Session fork and seed mechanics

Performance Characteristics

Write path

appendBatch() runs inside storage.transactionSync(): packs chunk runs, inserts storage records, increments revision, updates materialized summary — all atomic. A typical turn with 50 events (user message + request header + tool calls + assistant chunks + tool results + turn markers) produces ~10 storage rows after chunk packing.

Read path — session list

SESSION_SUMMARY_MATERIALIZED is a SELECT ... FROM dsh_sessions JOIN dsh_session_summaries with pagination by updated_at DESC. No event-table access. O(page size).

Read path — history pages

History reads use SELECT ... FROM dsh_session_events WHERE session_id = ? AND seq BETWEEN ? AND ? with a configurable page limit (max 65,536 events). Packed rows are decoded on read. The client pages backward; goal/title state comes from the projection cache, not from scanning the full log.

Boot-time repair

syncSummaries() runs once per DO activation. Detects sessions where the summary revision doesn't match the session revision and recomputes them. Bounded by stale session count (typically zero after normal shutdown).

Architecture Summary

Component Category Upstream Equivalent
DurableObjectSessionPersistence Replace JSONL file backend
Chunk packing Replace Not needed (file I/O has no row limit)
Materialized summaries Replace In-memory scan (not needed upstream)

Key observation: Session persistence is the largest Edge-owned replacement — ~1,000 lines of DO SQL code. But it stays strictly within the upstream SessionPersistence interface. All optimizations (chunk packing, materialized summaries) are invisible to upstream plugins — they see the same append/read/flush contract.

English

中文

Clone this wiki locally