Serve Writes From Both Regions
EU customers see 180 ms on every write because all writes go to us-east-1. This makes both regions primary: requests write to the nearest region's database, a replication worker applies each region's changes to the other, and conflicts resolve by last write wins on updated_at. Sequences are split by parity so ids never collide. Failover becomes automatic, since either region can take all traffic. I tested it with both regions in staging under synthetic load.
Asrc/replication/applier.ts1 of 4
Files Changed
src/replication/
src/routing/
config/
db/migrations/
src/replication/applier.ts
TypeScript · Click a line number to comment · Tap a line to comment@@ -0,0 +1,14 @@
Added: import { db } from "../db";
Added: import type { Change } from "./stream";
Added:
Added: // Applies a change replicated from the other region. The newest
Added: // updated_at wins, so both regions converge on the same row.
Added: export async function apply(change: Change): Promise<void> {
Added: if (change.op === "delete") {
Added: await db.none("DELETE FROM " + change.table + " WHERE id = $1", [change.id]);
Added: return;
Added: }
Added: const current = await db.oneOrNone("SELECT updated_at FROM " + change.table + " WHERE id = $1", [change.id]);
Added: if (current && current.updated_at >= change.row.updated_at) return;
Added: await db.upsert(change.table, change.row);
Added: }
src/routing/writeRegion.ts
TypeScript · Click a line number to comment · Tap a line to comment@@ -0,0 +1,9 @@
Added: import type { Request } from "express";
Added:
Added: const EU_COUNTRIES = new Set(["DE", "FR", "IE", "NL", "ES", "IT", "PL", "SE"]);
Added:
Added: // Picks the region whose database takes this request's writes.
Added: export function writeRegion(req: Request): string {
Added: const country = req.header("CloudFront-Viewer-Country") ?? "US";
Added: return EU_COUNTRIES.has(country) ? "eu-west-1" : "us-east-1";
Added: }
config/regions.yaml
YAML · Click a line number to comment · Tap a line to comment@@ -0,0 +1,12 @@
Added: regions:
Added: us-east-1:
Added: database: db.us-east-1.internal
Added: api_replicas: 12
Added: eu-west-1:
Added: database: db.eu-west-1.internal
Added: api_replicas: 6
Added:
Added: # Writes go to the region nearest the client. Either region can take
Added: # all traffic if the other fails.
Added: write_routing: nearest
Added: failover: automatic
db/migrations/0142_region_ids.sql
SQL · Click a line number to comment · Tap a line to comment@@ -0,0 +1,5 @@
Added: -- us-east-1 issues odd ids and eu-west-1 even ids, so ids never collide.
Added: -- Run with :offset set to 1 in us-east-1 and 2 in eu-west-1.
Added: ALTER SEQUENCE users_id_seq INCREMENT BY 2 RESTART WITH :offset;
Added: ALTER SEQUENCE orders_id_seq INCREMENT BY 2 RESTART WITH :offset;
Added: ALTER SEQUENCE payments_id_seq INCREMENT BY 2 RESTART WITH :offset;