Peer server and thin clients
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.
Start a peer server
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.
Query fuel
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.
Storage bootstrap
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.
Segment cache
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.
Failover
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 thin-client contract
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.
- Every transact and subscribe request sends a
protocol_version. This build speaks version 3 and accepts version 1 and later. An unsupported version isFAILED_PRECONDITION, never a silent downgrade. - Malformed input is
INVALID_ARGUMENT. An unknown database or entity isNOT_FOUND. Upstream loss isUNAVAILABLE. - Query results stream in chunks. A client concatenates them and stops at
last = true. Subscribe.from_basis_tis exclusive. The server backfills every later transaction without gaps, then continues live.- The subscription handshake advertises the heartbeat interval. A client treats silence for a few multiples of it as a dead upstream.
Transactgives 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.
Serving many principals
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 view hides attributes from a principal. Read authorization.
- A key grant decides which protection classes a principal can open. Read attribute protection.
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.
Language clients
| 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.