PostgreSQL WAL, Event Log & Real-Time Reactivity
In production environments, worker pods get evicted by Kubernetes, nodes encounter Out-Of-Memory (OOM) errors, and spot instances get reclaimed mid-turn.
Agent Substrate guarantees zero data loss, deterministic replay, and zero duplicate side-effects via its append-only PostgreSQL Write-Ahead Log (WAL) and an event-driven reactivity layer powered by PostgreSQL LISTEN / NOTIFY.
The Durability Architecture
Agent Substrate strictly decouples execution compute from persistent state. Agents never write raw SQL or manage database connections directly. Instead, the runtime uses a two-tier architecture:
- Kernel Protocols (
substrate.kernel.runtime): Pure abstract protocols (EventLogProtocol,SignalBusProtocol,InboxProtocol). - Infrastructure Backends (
substrate.infrastructure.runtime): High-performance PostgreSQL implementations wrapped aroundasyncpg.
1. Append-Only Event Log & Optimistic Concurrency
Every state delta, model token turn, and tool execution result is recorded sequentially in substrate_event_log:
CREATE TABLE substrate_event_log (
run_id TEXT NOT NULL,
seq INTEGER NOT NULL,
kind TEXT NOT NULL,
payload JSONB NOT NULL DEFAULT '{}',
ts TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (run_id, seq)
);Advisory Locking (pg_advisory_xact_lock)
To guarantee that two concurrent workers racing on the same agent run never clobber each other or interleave sequences out of order, EventLog.append() acquires a transactional PostgreSQL advisory lock hashed to the run_id:
async with conn.transaction():
await conn.execute("SELECT pg_advisory_xact_lock($1)", lock_key)
current = await conn.fetchval(
"SELECT COALESCE(MAX(seq), -1) FROM substrate_event_log WHERE run_id = $1",
run_id,
)
if current != expected_seq:
raise ConcurrentAppendError(
f"expected seq {expected_seq}, got {current}",
run_id=run_id,
expected_seq=expected_seq,
actual_seq=current,
)
# Insert new event at current + 1If an append conflicts with a concurrent worker or network retry, a ConcurrentAppendError is raised immediately, preserving linear state history.
2. Event-Driven Streaming via LISTEN / NOTIFY
Polling the database (SELECT ... WHERE seq > last_seq) introduces latency and exhausts database IOPS. Instead, Agent Substrate uses PostgreSQL's native LISTEN and pg_notify for sub-millisecond, push-based reactivity.
How Real-Time Reactivity Works
-
Transactional Notification: When an event is committed,
append()notifies the channel inside the same transaction:python await conn.execute("SELECT pg_notify($1, $2)", "substrate_evlog", run_id)Because
pg_notifyis transactional in PostgreSQL, notifications are delivered only when the transaction successfully commits. If a rollback occurs, no spurious notifications are fired. -
Dedicated Connection for
LISTEN:LISTENrequires a persistent, long-lived connection. TheEventLogallocates a dedicatedasyncpgconnection exclusively for notifications, ensuring client connection pools are never blocked or starved by streaming consumers. -
In-Memory Coroutine Waking: When a notification packet lands,
_on_notify()wakes in-memoryasyncio.Eventwaiters for that specificrun_id, allowing real-time tailing with near-zero latency. -
Safety Fallback Polling (Zero Missed Events): Because PostgreSQL notifications are delivered best-effort over TCP without message retention, a 2.0-second safety poll backstop runs concurrently. If a temporary network blip occurs, the listener self-heals and drains missing records automatically.
from substrate.infrastructure.runtime.event_log import EventLog
event_log = EventLog(pool, dsn="postgresql://...")
# Stream agent execution events in real time
async for entry in event_log.tail(run_id, from_seq=0):
print(f"[{entry.seq}] {entry.kind}: {entry.payload}")3. Hot Waking & The Signal Bus
When an agent enters hibernation waiting for human approval or an external webhook, it suspends execution and yields its worker thread.
To wake a suspended agent without active polling:
- An approval action or webhook calls
SignalBus.signal(run_id, name, payload). - The signal is stored in
substrate_signals. - The run status in
substrate_run_queueis transitioned from'suspended'to'pending'. - PostgreSQL sends a notification:
python await conn.execute("SELECT pg_notify('substrate_sched', $1)", run_id) - Background schedulers wake up instantly and lease the run to the next available worker.
4. Pod Eviction & Crash Replay
If a worker node crashes mid-execution (e.g. at Step 3 of a 5-step task):
- A standby worker leases the run from
substrate_run_queue. - The worker replays the event log from
seq = 0toseq = 3. - Memoized Effect Hits: Completed tool calls and model responses are loaded from the database cache in under 5ms. The agent does NOT re-query external APIs, duplicate database writes, or double-bill model tokens.
- Execution seamlessly resumes at Step 4.
Next Steps
- Zero-Cost Pauses & Hibernation — Deep dive into
SuspendInterruptand human approval gates. - Kernel Primitives Reference — Review
EventLogProtocol,SignalBusProtocol, andActoraddress specs. - Subsystem Architecture — Understand the 4-tier layer hierarchy.