Every source behind this page, graded. This session's network policy
allowed github.com and gitlab.com only, so the wall is repository record end to end:
incident reviews, source files, RFCs, issues and in-repo vendor docs. Engineering-blog,
paper and talk tiers are absent because their hosts were unreachable, not because the
material was judged and cut; the hunt section says where those layers live.
Postmortem
GitLab2024-10
Incident review: pipelines not completing
The definitive stale-read incident write-up: misrouted Sidekiq reads, 37 hours,
repeated premature mitigation, root cause found only through a per-worker replica-read
metric. Includes the linked incident issue (#18676) and the revert MR (168630).
Carry forwardStaleness has no alarm; graph the routing invariant itself.
gitlab.com/gitlab-com/gl-infra/production/-/issues/18681
Postmortem
GitLab2025-10
Incident review: INC-4589 / INC-4641, database saturation
A six-step cascade from replica CPU saturation to site-wide pool exhaustion, twice in
three days, with the load balancer's primary-fallback named as an amplifier in the
lessons learned.
Carry forwardBudget the fallback path; lag caused by load makes fallback the wrong direction.
gitlab.com/gitlab-com/gl-infra/production/-/issues/20692
Postmortem
GitLab2017-02
Postmortem of database outage of January 31
The canonical replication-lag disaster, read from the blog's markdown source at a
pinned 2017 commit: lag broke replication entirely, and the manual re-sync procedure
destroyed the primary's data directory.
Carry forwardThe lag-repair runbook is part of the consistency design; make the destructive step unable to hit the primary.
www-gitlab-com @ 026a78dd, source/posts/2017-02-10-postmortem...
Postmortem
GitLab2024-10
Incident issue: pipelines not completing and stuck merge requests
The live incident record behind review #18681: three rounds of investigation, two
red-herring subsystems, and the note where a graph of replica reads by
data_consistency: always workers cracked the case.
Carry forwardDuring an incident, ask "who is reading replicas that should not be" early; it is cheap to graph.
gitlab.com/gitlab-com/gl-infra/production/-/issues/18676
Source
GitLabmaster, 2026-09
load_balancing/sticking.rb
The production sticking layer: per-client LSN in Redis with a 30-second TTL, and Lua
scripts that parse and compare LSNs atomically so racing requests cannot regress the
stored position.
Carry forwardThe token store update is a compare-and-swap, not a write; get it atomic or lose positions under concurrency.
gitlab-org/gitlab lib/gitlab/database/load_balancing/sticking.rb
Vendor
GitLabmaster, 2026-09
Database Load Balancing (administration doc)
The operational envelope around the code: 30-second primary sticking released early
when replicas catch up, and lag thresholds (8 MB, 60 s) that evict replicas from the
candidate pool.
Carry forwardRouting and health-filtering are one feature; document both numbers together.
doc/administration/postgresql/database_load_balancing.md
Vendor
GitLabmaster, 2026-09
Sidekiq worker attributes: data_consistency
The asynchronous half of the design: jobs enqueue with the primary's LSN;
:sticky and :delayed workers get replicas guaranteed caught up
to enqueue time, or a retry, or the primary. Every worker must declare a mode, enforced
by RuboCop.
Carry forwardMake consistency a required, linted, per-callsite declaration; defaults are how the wrong reads reach replicas.
doc/development/sidekiq/worker_attributes.md
Source
Rails / GitHub2019-01
PR #35073: automatic database switching
The PR that upstreamed GitHub's approach into Rails: two-second post-write window per
session, with the author noting GitHub's production variant runs five seconds plus a
replication-delay circuit breaker, and a reviewer flagging the query cache as a
remaining stale-read hole.
Carry forwardThe framework default is the crude version of what its authors run; read the PR thread for the missing parts.
github.com/rails/rails/pull/35073
Source
Railsmain, 2026-09
database_selector resolver
SEND_TO_REPLICA_DELAY = 2.seconds, a timestamp in
session[:last_write], and a comparison. The whole shipped mechanism is
thirty lines.
Carry forwardKnow exactly how little the default does before trusting a workflow to it.
activerecord/.../database_selector/resolver.rb
Source
OpenStreetMap2021-05 to 2026-03
PR #3201: use database replicas for read requests (closed unmerged)
A five-year attempt to adopt Rails' replica switching in a mature application,
blocked by a framework migrations bug and dependency gaps, closed with "it's probably
easier to start afresh, rather than rebase this PR." Its predecessor (#2634) has been
open since 2020.
Carry forwardRetrofitting read-write splitting into a grown codebase is a project, not a config flag; budget it like one.
github.com/openstreetmap/openstreetmap-website/pull/3201
Source
Wikimediamaster, 2026-09
ChronologyProtector.php
The oldest complete implementation in the corpus, documented like a design paper in
its header: client-ID-keyed positions, a ten-second cookie window sized to cross-DC
replication, a one-millisecond store budget, and an explicitly accepted degraded mode.
Carry forwardWrite the store's requirements and the failure behaviour down; this comment block is the best spec of the pattern anywhere.
wikimedia/mediawiki includes/libs/Rdbms/ChronologyProtector.php
ADR
Vitess2020-10
RFC: Read After Write (#6843)
The complete GTID-based design: MySQL returns the GTID in the OK packet, VTGate
wraps it, replicas run WAIT_FOR_EXECUTED_GTID_SET. Recommends failing on
timeout rather than escalating to the primary. Open since 2020; the user ask (#4718)
predates it by 18 months.
Carry forwardThe fail-on-timeout position is the road less taken; steal its reasoning when your primary cannot absorb fallback.
github.com/vitessio/vitess/issues/6843
Source
Vitess2021-12
Issue #9307: NULL lag treated as zero
A maintainer-filed bug: with the source unreachable, seconds_behind_master
is NULL, was coerced to 0, and unboundedly stale replicas passed health checks. Fixed in
PR #9308.
Carry forwardUnknown lag is infinite lag; audit every place a lag probe's error path defaults to zero.
github.com/vitessio/vitess/issues/9307
Source
ProxySQL2019-07
Issue #2134: causal reads on MariaDB/Galera
Why the proxy cannot always save you: ProxySQL's GTID causal reads require the
server's session_track_gtids, which MariaDB did not provide. The guarantee
is only as available as the weakest layer's cooperation.
Carry forwardBefore promising read-your-writes through a proxy, verify the specific server flavour exposes session GTID tracking.
github.com/sysown/proxysql/issues/2134
Vendor
MariaDB24.02, 2026-09
MaxScale ReadWriteSplit: causal_reads
Seven modes spanning session, service and cluster causality, wait-based and
route-based variants, a 10-second budget, primary retry on timeout, and honest warnings
about the fast modes collapsing onto the primary under writes.
Carry forwardThis one enum is the whole decision space; use it as a checklist even off MariaDB.
MaxScale Documentation/Routers/ReadWriteSplit.md
ADR
Cockroach Labs2018-06
RFC: Follower reads
The strong-by-default database's opt-out: closed timestamps trailing real time by
about five seconds let historical reads run on followers, "away from foreground
traffic".
Carry forwardIn a strongly consistent store the decision inverts: you choose which reads may be stale, with an explicit bound.
cockroachdb docs/RFCS/20180603_follower_reads.md
ADR
Cockroach Labs2021-05
RFC: Bounded staleness reads
Generation two: the reader states a staleness budget
(with_max_staleness) and the system minimises staleness inside it, "more
tolerant to replication lag" than a fixed historical timestamp.
Carry forward"How stale may this read be" is a better API than "read at this time"; consider exposing the budget to callers.
cockroachdb docs/RFCS/20210519_bounded_staleness_reads.md
ADR
MongoDBmaster, 2026-09
Driver specification: causal consistency
The token pipeline as a formal spec: every server response carries an
operationTime; drivers must store it in the session and replay it as
afterClusterTime on subsequent reads, without validating it.
Carry forwardIf you build a driver-level token, spec the MUSTs like this; the guarantee lives or dies on unconditional token propagation.
mongodb/specifications causal-consistency.md
Vendor
Cloudflare2026-09
D1 read replication: Sessions API
The 2025 incarnation: replicas "may be arbitrarily out of date", sessions guarantee
sequential consistency via bookmarks, and the application carries the bookmark between
requests itself, shown as an x-d1-bookmark header.
Carry forwardEven fully managed platforms hand the carrier problem back to you; plan where the token rides in your protocol.
cloudflare-docs d1/best-practices/read-replication.mdx
Vendor
AWSarchived 2023
DynamoDB: read consistency and capacity pricing
Weak-by-default with a priced opt-in: eventually consistent unless
ConsistentRead is set; the strong read costs twice the capacity, is
unavailable on global secondary indexes, and may return a 500 during network trouble.
Carry forwardStrong reads are a budget line and an availability trade, not a checkbox; price them into the design review.
awsdocs HowItWorks.ReadConsistency.md
Source
GitHub2026-09
freno: cooperative replication-lag throttler
The write-side complement: a raft-replicated service that throttles bulk writers when
replica lag crosses a threshold, keeping replicas valid for readers; its README names
"mitigating write-then-read pains of master reads" as a use.
Carry forwardYou can also buy read-your-writes by slowing writers; for bulk and migration traffic it is often the cheapest lever.
github.com/github/freno
Source
PostgreSQL2020-2026
The wait-primitive commit saga
Three landings: a 2020 revert, pg_wal_replay_wait() committed 2024-04-02
and reverted 2024-04-11 (v17 shipped without it), and WAIT FOR committed
2025-11-05 for v19, with a recovery-deadlock fix as late as 2026-09-12.
Carry forwardWaiting for replication interacts with locks, snapshots and recovery; whoever implements it, test those three interactions first.
postgres/postgres commits, src/backend/commands/wait.c
Source
Fly.iomain, 2026-09
LiteFS proxy_server.go
The pattern reinvented at the edge for SQLite: a __txid cookie, replicas
polled every millisecond up to five seconds, cookie expiring after five minutes, writes
forwarded to the primary.
Carry forwardThe design costs about 200 lines when the token is a single integer; the hard part is everything around it.
superfly/litefs http/proxy_server.go
Vendor
etcdv3.5 docs, 2026-09
etcd API guarantees
The counter-default for contrast: "etcd ensures linearizability for all other
operations by default." A coordination store sells agreement, so it pays the read-time
cost up front and lets callers opt down instead.
Carry forwardDefaults follow the product's promise; decide what yours is before copying anyone's default.
etcd-io/website learning/api_guarantees.md