pub struct ReadReplicaConfig {
pub urls: Vec<String>,
pub pin_after_write: Duration,
pub max_lag: Option<Duration>,
pub health_probe_interval: Duration,
}Expand description
Read-replica configuration for a PostgreSQL adapter (#407).
§Routing model
FraiseQL’s read/write partition is static: compiled GraphQL queries execute
through the adapter’s structurally read-only methods (execute_where_query*,
execute_with_projection*, execute_parameterized_aggregate*, explain_*,
relay pagination), and those route to a replica selected round-robin. The
mutation pipeline (execute_write) and every mixed-use or
administrative surface (execute_raw_query, execute_row_query, query stats,
health checks, schema DDL) always run on the primary — a surface that can
write is never routed to a replica.
§Read-your-writes
Every mutation-pipeline write arms a shared watermark; for
pin_after_write afterwards, reads route to the
primary so replication lag cannot serve a client its own stale write. The
window is an operator assertion about worst-case replica lag: writes that
bypass the mutation pipeline (raw SQL, out-of-band jobs) do not arm it, and a
replica lagging beyond the window can serve stale — but never torn — rows.
§Failure behaviour
A replica that is unreachable at boot refuses to boot (a configured-but- unusable pool must not downgrade silently). A replica that fails at runtime is skipped for that acquisition — the next replica is tried, then the primary — so replica loss degrades read capacity, never read availability.
§Bounded staleness
max_lag turns the pin window’s assertion into a
measurement: a replica is only eligible while its last probed replay lag,
aged by how long ago that probe ran, is still inside the budget.
That sum is a true upper bound rather than an estimate — replay lag grows at most one millisecond per millisecond of wall clock, so however stale the probe is, the lag cannot have grown by more than its age — and it makes the gate self-closing: an unrefreshed probe ages past any budget on its own. A replica whose lag cannot be measured at all is never eligible; unknown staleness is not zero staleness.
Fields§
§urls: Vec<String>Connection URLs of the read replicas, tried round-robin. Must be non-empty.
pin_after_write: DurationHow long after a mutation-pipeline write reads keep routing to the primary.
Must be at least the worst replication lag the operator is prepared to tolerate; within it, a client is guaranteed to read its own writes.
max_lag: Option<Duration>Bounded staleness: the most replication lag a replica-served read may
carry. None disables lag-based routing entirely — replicas are then
selected round-robin regardless of how far behind they are, which is the
behaviour before this option existed.
A replica whose lag cannot be measured — never probed, last probe failed, no transaction replayed yet, or promoted out of recovery by a failover — is not eligible while this is set. Unknown staleness is not “zero staleness”, and the primary is always a correct answer.
Must be strictly greater than health_probe_interval:
eligibility ages the last probe, so a budget no larger than the probe
period would make even a perfectly caught-up replica ineligible for part
of every cycle.
health_probe_interval: DurationHow often each replica is probed for recovery state and replay lag.
Probing is unconditional when replicas are configured: the boot health
check runs once, and a replica promoted by a failover after boot is a
writable server that a pg_is_in_recovery() reading taken at startup can
never notice.
Trait Implementations§
Source§impl Clone for ReadReplicaConfig
impl Clone for ReadReplicaConfig
Source§fn clone(&self) -> ReadReplicaConfig
fn clone(&self) -> ReadReplicaConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more