Documentation

Observe availability health

Peryx exposes the group roster, node roles, readable frontiers, and replica lag through bounded, role-filtered surfaces. See [availability] for configuration and availability contracts for acknowledgement guarantees.

Every surface below filters its fields to the caller's class, sends Cache-Control: no-store, and stamps its own observation time, so a stale render shows as age rather than passing for health. None of them traverse live membership or storage state per request.

The topology view

The topology surface is one immutable picture of the group taken at a single instant: the mode, the group identity, the configured roster with each node's datacenter and role, and this node's own live frontier and liveness. Availability modes documents the snapshot and its per-class filtering in full; read it as the availability topology page at /admin/topology, or as JSON from GET /+availability/topology. The snapshot does not poll peers, so non-local liveness stays unknown. Read heartbeat health from a dc or ha writer's replication documents (see Node liveness) rather than from the snapshot.

An open operator page keeps that picture current without polling each node. GET /+availability/topology/stream is a bounded Server-Sent Events feed of the same role-filtered snapshot. It sends the current snapshot on connect, then one event only when this node's frontier or liveness moves, so its traffic tracks the change rate rather than the roster size or the number of open pages; the observation time advancing on its own emits nothing, and an idle group carries only a keep-alive comment every fifteen seconds. Each event's id increases, so a browser resumes from Last-Event-ID on reconnect. A reader too slow to keep up coalesces to the latest snapshot rather than a backlog, because each sample re-reads live state and the connection buffers nothing. The topology page shows a feed badge that reads Reconnecting or Offline while the browser retries, so a paused feed freezes the snapshot time rather than passing stale data for fresh. The stream inherits the caller's credentials and no-store policy from the one-shot endpoint, so it never widens what a page already reveals.

Placement health

The placement surface reports how the store's bytes are placed: how many artifacts serve from local storage, how many have no local bytes but a reachable upstream, and how many have neither. Read it as the artifact placement-health page at /admin/placements, or as JSON from GET /+availability/placements.

The whole-store counts need operator:read and are aggregated before serialization, so the summary never scales with the object count. A per-digest table needs administration:read, because a digest identifies an artifact; it pages in digest order, bounded at the supported limit with a cursor to resume. Each row carries a digest with its source and byte availability alone, never a file path, repository, or owner, so inspecting convergence exposes no tenant data. An operator who cannot read the rows still reads the counts.

Use the counts to watch a replica converge: a rising remote-only count on a node that should hold bytes locally names a store that has applied metadata ahead of the blobs it references, which the derived-view frontier holds back from readers until the bytes land.

Pending operations

The operations surface reports the admitted writes the node retains, bucketed by the client-facing status each reads: pending while a write is in flight within its retention deadline, published once it finalizes, failed when it gives up, and expired when it outlives its deadline without finalizing. Read it as the pending-operations page at /admin/operations, or as JSON from GET /+availability/operations.

The whole-ledger counts need operator:read and are aggregated before serialization, so the summary never scales with the number of retained writes. A per-operation table needs administration:read, because an operation id identifies a write; it pages in operation-id order, bounded at the supported limit with a cursor to resume. Each row carries an operation id with its status, when its record last changed, and when it may be pruned, never the response bytes, the repository, or the owner, so inspecting a write's convergence exposes no tenant data. An operator who cannot read the rows still reads the counts.

An expired write is not a definite failure: the retention deadline is the client's wait, not the write's, so a durable completion may have happened after the client stopped polling. A terminal record is pruned once its deadline passes, while a still-pending one is kept, so a rising expired count names writes whose durability a client could not confirm within its deadline rather than writes known to have been lost.

The operation surface consumes the shared OperationObserver contract. An observation contains an owner-neutral source, authority epoch, serial, and operation kind. Content owners emit observations; availability code aggregates them without importing owner schemas or route types.

Liveness and readiness

The topology and placement surfaces describe the group; the load-balancer probes describe one node's fitness to receive traffic. GET /+health stays live while the process can answer at all; GET /+ready fails a node whose local metadata or blob store cannot serve; GET /+ready?writes=true fails a replica, which serves reads but rejects mutation. GET /+status is the detailed operator surface, filtered to the caller's class the same way the topology view is. Point an ingress rule at the probes and reserve the topology and placement pages for authenticated operators.

Reading at a consistent point

A replica serves reads only up to its readable frontier: the lowest metadata serial every required view has rebuilt to. A record the replica has stored but not yet reflected in its search index or rendered pages stays below that frontier, so a client never pairs new metadata with an old view. The frontier is durable and monotonic, so a restart never exposes a record a view had not applied. A replica exports how far its views trail the metadata it has committed as peryx_ha_distributed_readable_serial, which the placement and topology surfaces complement with per-node liveness.

Send every mutation to the writer. A replica rejects uploads, deletes, and other mutations with 503 Service Unavailable, preventing a misrouted write from diverging the copy.

Mode scope

Availability surfaces exist only under dc or ha. With mode = "none", the process registers no availability routes, metrics, listeners, workers, or lifecycle handles. It also creates no distributed-domain tables. General request, job, and storage metrics remain available because they are not part of distributed coordination.

Each surface reports only proven coordinator state. An absent or unknown peer observation never reads as healthy.

On this page