Single-region monolith to active/active in 14 weeks
The situation
A European payments processor handling roughly 40 million card authorisations a month, all of it served from a single region by a Rails monolith with a 900GB Postgres instance behind it. Checkout p99 sat at 340ms and the business had committed to a payment scheme SLA of 99.95% availability with a documented regional failover — which they could not demonstrate. Their tested failover was a 42-minute manual restore from snapshot.
The forcing function was regulatory: an operational resilience assessment gave them two quarters to prove a regional outage would not take the service down.
What we did
- Split the write path from the read path first. Authorisation is synchronous and must stay strongly consistent; settlement, reporting and webhook delivery do not. Moving those three into an event-driven pipeline took 61% of the load off the primary before any migration started.
- Cell-based routing. Rather than replicating everything everywhere, merchants were sharded into cells pinned to a home region, with the second region holding a warm promotable replica per cell. Failover moves cells, not the entire estate, so blast radius is bounded.
- Kubernetes with strict tenancy. Three-AZ EKS in each region, Karpenter for capacity, on-demand floor for the authorisation path and spot for settlement workers. Gateway API at the edge with per-merchant rate limiting.
- Latency work driven by profiles, not guesses. Continuous profiling identified two N+1 query patterns and a JSON serialisation hotspot responsible for 210ms of the p99 on its own. Connection pooling via PgBouncer in transaction mode removed another 60ms of queueing under peak.
- Failover as a drill, not a document. Region promotion is now a single ArgoCD-driven procedure, rehearsed quarterly against production with the regulator's assessor invited to watch the last one.
- Sector
- Payments / regulated fintech
- Scale
- 40M auths/month, 900GB primary
- Duration
- 14 weeks build + 6 weeks migrate
- Team
- 1 principal, 3 engineers
- Model
- Build & migrate, milestone-based
- Stack
- EKS · Aurora · Kafka · Envoy · ArgoCD
# regulator-witnessed promotion
t+00s health check fails eu-west-1
t+11s edge drains region, TTL 10s
t+26s consensus lease acquired
t+48s replica promoted, WAL replayed
t+71s writes accepted us-east-1
t+90s all SLIs green
# 4 auths failed, all retried by scheme
Before / after
| Metric | Before | After (90d) | Delta | How measured |
|---|---|---|---|---|
| Checkout p99 latency | 340 ms | 45 ms | −86.8% | edge histogram, 1m buckets |
| Checkout p50 latency | 86 ms | 19 ms | −77.9% | edge histogram |
| Regional failover time | 42 min | 90 s | −96.4% | quarterly drill, wall clock |
| Availability (rolling 30d) | 99.87% | 99.982% | −86% error rate | successful auth ratio at edge |
| Deploy frequency | 4 / month | 124 / month | ×31 | ArgoCD sync events |
| Primary DB write load | 100% | 39% | −61% | pg_stat, peak hour |
| Infrastructure cost | $214k / mo | $248k / mo | +15.9% | two regions — deliberate trade |
"The number that mattered to our board was 90 seconds. The number that mattered to our engineers was that nobody had to be awake for it."
— VP Engineering, payments processor