org.llm4s.agent.graph.postgres
Members list
Type members
Classlikes
A durable org.llm4s.agent.graph.Checkpointer in a PostgreSQL database: threads, their checkpoint histories, pending writes, event logs, effect records and run claims, shared by every runtime on every machine that opens a store over the same database and schema. It is the store for running one agent service on several machines (Stage 5, design 4.50).
A durable org.llm4s.agent.graph.Checkpointer in a PostgreSQL database: threads, their checkpoint histories, pending writes, event logs, effect records and run claims, shared by every runtime on every machine that opens a store over the same database and schema. It is the store for running one agent service on several machines (Stage 5, design 4.50).
Open it with PostgresCheckpointer.open, over a pool of its own, or PostgresCheckpointer.create, over a DataSource the caller already has; close it with close. It meets the Checkpointer contract and passes CheckpointerContract from llm4s-agent-testkit:
- '''Atomic, fenced commits.''' Every call that writes is one transaction, which first locks the thread's row (
SELECT ... FOR UPDATE) and then checks the claim's token, aCommit.fence's claim on another thread, and the parent checkpoint, before it allocates event numbers from the row and writes. A call that locks two threads' rows- a fenced commit or delete - locks them in the order of their ids, so two such calls never deadlock.
- '''The database decides time.''' A claim's expiry and a retention policy's age are judged by the database server's clock (
clock_timestamp(), read once the call holds its locks), never a host's: skew between the machines sharing the store changes nothing. Age is measured from the commit time the store stamps, by that clock, on every checkpoint and event row - never from the producer'sCheckpoint.createdAtor eventtimestamp, which stay as the producer's record. Theclocka runtime is given still schedules its renewals. - '''Fencing tokens''' come from one sequence for the whole schema, so they increase across restarts, releases, takeovers and deleteThread, and are never issued twice.
- '''History, retention, deletes and children''' behave exactly as in the SQLite store: every superseded checkpoint is kept until
prune,retractTurnor deleteThread removes it; a deleted thread leaves a tombstone of its event numbering; a parent's children are listed in the order their first commits landed. - '''Data only.''' Checkpoints, pending writes, events and effect records are stored as JSON text and decoded on read, so nothing executable is stored.
- '''Change notification by polling''' for now: a subscription reads the log once per
WatchPolicy.pollInterval(theCheckpointer.awaitEventsAfterdefault).LISTEN/NOTIFYreplaces it in a later slice.
Reads run in a REPEATABLE READ, read-only transaction, so what one call reads is one snapshot; they never wait for a writer.
'''Every call returns within a bound''', as the Checkpointer contract requires (#1919): the pool's connection timeout plus PostgresCheckpointerConfig.callTimeout, plus the time a rollback takes. The call timeout is set on the server for the transaction (statement_timeout, lock_timeout, idle_in_transaction_session_timeout) and enforced on the client as well: a call that reaches it has its connection aborted and discarded from the pool, so a stalled network cannot hold it either. A call that reaches the bound fails with a ProcessingError. Like any networked store, a call that times out while its COMMIT is in flight cannot know whether the commit landed; the claim's fencing keeps that safe, as a later commit on a stale view is refused.
'''Interrupts.''' An interrupt flag already set when a call begins decides nothing: it is cleared for the call and set again when the call returns. An interrupt that lands during a call (on a virtual thread, it closes the connection's socket) ends that call with CancelledError or a failed result, and the connection is discarded, so the store stays usable by every other thread.
Every failure of the database itself is a ProcessingError, and so is any call after close. Safe to call from any number of threads: each call takes a connection of its own from the pool.
Attributes
- Companion
- object
- Supertypes
Attributes
- Companion
- class
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
PostgresCheckpointer.type
How a PostgresCheckpointer uses its database.
How a PostgresCheckpointer uses its database.
schema: the PostgreSQL schema its tables live in,llm4sby default, so the store can share a database with other tables (and two stores, in two schemas, can share one database without seeing each other). It is created if it does not exist. A lower-case SQL identifier: a letter or_, then letters, digits or_, at most 63 characters.callTimeout: how long one call may hold its connection - every statement it runs, the waits for row locks another instance holds included - before it fails, changing nothing. It is set on the server as the transaction'sstatement_timeout,lock_timeoutandidle_in_transaction_session_timeout, and enforced on the client too: a call still running when it passes has its connection aborted and discarded, so a call whose network stalls fails at the bound rather than waiting for the socket.connectionTimeout: how long a call waits for a connection from the store's own pool (see PostgresCheckpointer.open); at least 250 milliseconds, HikariCP's minimum. A caller-supplied pool (PostgresCheckpointer.create) keeps its own setting, which then takes this one's place in the bound.maxPoolSize: the size of the store's own pool; ignored for a caller-supplied one.
'''The bound.''' Every call returns within connectionTimeout + callTimeout, plus the time it takes to roll back or discard a connection: the bound the Checkpointer contract asks a store to document (#1919). Keep it well inside ClaimPolicy.ttl - ClaimPolicy.renewEvery (the defaults, 5 + 5 seconds, are inside 30 - 10).
Durations are rounded up to whole milliseconds and must be positive and at most Int.MaxValue milliseconds; apply and the with* setters throw IllegalArgumentException for an invalid value, and PostgresCheckpointerConfig.of returns a ValidationError.
Attributes
- Companion
- object
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- class
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type