Routes read queries to primary or replica nodes based on session stickiness, read-your-writes requirements, and measured replication lag so stale reads fail visibly instead of silently misinforming users.
Package status: AI-assisted reference package. Static package validation has passed; implementation scenarios remain not run and human domain review is required before stable adoption.
Decision
Read scaling through replicas is adopted only together with an explicit routing contract. Not every read may use a replica. After a successful write, the same session must observe read-your-writes until a candidate replica proves that it has replayed the session's last-write position; elapsed wall-clock time alone never ends that guarantee. A bounded sticky window may reduce replay checks, but after the window the router still verifies the write token or remains on primary. Queries that power balances, authorization state, or post-mutation confirmation always target the primary. Analytics and catalog browsing may tolerate bounded staleness when lag probes confirm the replica is within policy. When lag is unknown or exceeds threshold, routing fails safe to the primary and emits telemetry rather than silently serving stale rows.
Scope
- Application-level read routing for relational or document stores with asynchronous replication.
- Session stickiness after writes and per-query-class routing rules.
- Lag measurement, threshold enforcement, and fallback when replicas are unhealthy.
- Staged rollout of replica-eligible query classes and rollback-to-primary migration controls.
- Observability for route decisions and stale-read prevention.
Outside this block
- Multi-region active-active conflict resolution.
- ORM connection pool vendor configuration beyond what the contract requires.
- Cache coherence layers that sit above the database; those require their own block.
Contract
- Every read path declares one query class from the shared vocabulary: session_state, reporting_aggregate, billing_balance, or catalog_browse; the class maps to primary-only, replica-if-lag-ok, or replica-tolerates-staleness according to the routing matrix.
- After any successful write, the initiating session carries a datastore replay-position token. A profile-defined sticky-primary window is a minimum routing period, not an expiry for the consistency guarantee.
- Reads that require read-your-writes resume on a replica only after that replica confirms a replay position at or beyond the session token. If the datastore cannot compare positions, those reads remain on primary.
- Replica reads proceed only when the selected replica reports lag at or below the profile maximum; otherwise the router selects primary and records lag_exceeded.
- When lag telemetry is missing for a candidate replica, the router treats lag as unknown and selects primary for session_state and read-your-writes classes.
- If all replicas are unavailable or stale, reads fall back to primary; writes fail closed when primary is unavailable and are never directed to a replica.
- Route decisions and measured lag milliseconds are emitted to observability for each query class to support SLO review and incident response.
- Replica routing rolls out by query class in declared stages; until a class is enabled for replicas, it routes primary-only even when other classes may use replicas.
- Rollout rollback on stale-read incident or lag SLO breach returns all query classes to primary-only-all-classes until operators re-enable staged routing.
Implementation guidance
- Centralize routing in a thin data-access layer so services do not embed ad hoc primary/replica switches.
- Use heartbeat probes for general lag policy and replay-position comparison for read-your-writes; a low aggregate lag estimate is not proof that one specific write is visible.
- For cross-service reads after a write, propagate the last-write token on internal calls so downstream services do not accidentally read from a stale replica.
Failure handling and safeguards
- Do not expose different error shapes for primary versus replica failures unless required; prefer a unified unavailable response for user-facing reads while logging the route cause internally.
- Alert when all replicas remain stale beyond the SLO window so operators can fail over or remove bad nodes.
- Reporting jobs that intentionally use stale replicas must label results with the maximum observed lag timestamp.
Verification and operations
- Chaos-test replica lag beyond the sticky window and verify read-your-writes paths remain on primary until a replica confirms the last-write position.
- Measure percentage of reads by target, lag breach rate, and primary fallback frequency.
- Prove billing_balance and session_state query classes never register a replica target in integration tests.
- Stage-enable catalog_browse first, then reporting_aggregate, verifying primary-only behavior for classes not yet in the active stage.
- Drill rollout rollback and confirm all classes return to primary-only before any staged re-enablement.
The executable-looking examples in this package are fixtures and acceptance contracts. Run static validation on the package structure and metadata, then implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map query classes, session tokens, and lag probes to its datastore capabilities.
- PostgreSQL hot standby and Jepsen-style consistency vocabulary inform the contract but do not mandate a specific engine.