A peer server is a peer hosted as a standalone process. It exposes query, pull, transact, datom scans, and transaction ranges over gRPC.
Use it for a language that has no peer library. For a language with a peer library, embed the peer instead. An embedded peer queries in-process.
corium peer-server --db people --listen 0.0.0.0:4336 \
--transactor http://127.0.0.1:4334
One process hosts one database. Run one process per database.
| Flag | Default | Effect |
|---|---|---|
--db <name> | None. Required. | Database to host. |
--listen <addr> | 127.0.0.1:4336 | gRPC listen address. |
--max-fuel <n> | 10000000 | Ceiling on datoms touched per query. |
--metrics-listen <addr> | None | Prometheus endpoint at /metrics. |
The peer server takes the same connection flags as the other client commands, and the same serving flags as the transactor.
Fuel bounds a runaway query. A client can request less fuel. fuel = 0
requests the server default. The server clamps every request to --max-fuel.
An exhausted budget returns INVALID_ARGUMENT.
By default the peer server replays the log from basis 0 at startup. On a large database that is slow.
corium peer-server --db people --peer-bootstrap \
--storage-key file:/etc/corium/storage.key
--peer-bootstrap reads the published snapshot from storage and subscribes
from the index basis. The peer needs network reach to the storage backend, and
a build with the matching storage feature.
The transactor supplies the connection details through its GetStorageInfo
call, using the read-only credential that you configured. See
storage backends.
A peer server can keep a local SSD cache of segments.
| Flag | Default | Effect |
|---|---|---|
--segment-cache-dir <path> | None | Dedicated directory for the cache. |
--segment-cache-capacity <size> | None. Required with the directory. | Disk capacity, for example 256GiB. |
--segment-cache-memory <size> | 64MiB, or the capacity when smaller | Memory front tier. |
A size accepts the suffixes B, KiB, MiB, GiB, TiB, kB, MB, GB,
and TB.
The cache requires --peer-bootstrap. Without it, the process fails at
startup with a clear message.
Give the cache a dedicated directory. Corium manages the contents.
Pass every transactor endpoint, active first:
corium peer-server --db people \
--transactor http://txor-a:4334,http://txor-b:4334
The peer rotates the list on failure. A standby rejects subscriptions with a
standby status, which the peer treats as a reason to try the next endpoint.
See high availability.
The wire contract is documented in
thin-client-protocol.md.
The canonical schema is crates/corium-protocol/proto/corium.proto.
Six rules matter to an operator.
protocol_version. This build
speaks version 3 and accepts version 1 and later. An unsupported version is
FAILED_PRECONDITION, never a silent downgrade.INVALID_ARGUMENT. An unknown database or entity is
NOT_FOUND. Upstream loss is UNAVAILABLE.last = true.Subscribe.from_basis_t is exclusive. The server backfills every later
transaction without gaps, then continues live.Transact gives read-your-writes on the serving peer before it responds.A client is conformant when it reproduces the behavioral corpus in
tests/conformance.
Version 3 adds the sealed value tag. A client older than version 3 never
receives a sealed value. An unopened value reaches it as the tagged EDN
element #corium/redacted, which every EDN reader parses.
A peer server serves every client from one process and one database value. Which facts a client sees is a policy question, not a process question.
A principal whose view hides attributes cannot Transact, and it cannot
Subscribe. Transaction data is opaque bytes by the time authorization runs.
A subscription proxies the stream of the transactor. Neither call can honor a
filter, so the server refuses rather than serve unfiltered data.
| Client | Location |
|---|---|
| Rust | corium-peer, corium-client |
| Python | clients/python |
| Java | clients/java |
| Clojure | corium-cljrs, the corium.api namespace |
The Python and Java clients each offer two peers behind one interface.
| Peer | Where it runs |
|---|---|
LocalPeer | Embeds a full peer in the process. It indexes and queries in process, and it talks to a transactor directly. |
RemotePeer | Connects to a peer server over gRPC. |
Both produce the same database values, and every time view works the same way on both. Only a remote peer can join across databases in one query.
An embedded peer can also read published segments straight from storage, and it can hold its own class keys. Use it where the keys must stay in the application process.
Can you improve this documentation? These fine people already did:
Claude & Casey MarshallEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |