Coding problem · Easy · Design & Data Structures

Read-Your-Writes Replica Router

Easy Practical tasks

Profile pages read from an asynchronous read replica, and users complain that their own edits disappear after saving. Implement the routing rule that gives read-your-writes:

Router(maxLagMs):

  • write(user, nowMs) — writes always go to the primary; remember the time of the user's latest write and return "primary".
  • read(user, nowMs, replicaLagMs) — the replica has applied every write made at or before nowMs − replicaLagMs. Return "primary" if the replica is unhealthy (replicaLagMs > maxLagMs) or if it hasn't applied this user's latest write yet; otherwise return "replica".

Times stand in for log positions (Postgres LSN / MySQL GTID) to keep the problem simple. See Read-Your-Writes and Monotonic Reads.

Example 1

Input: ["Router","write","read","read","read","read"]
[[5000],["ada",1000],["ada",1100,300],["bob",1100,300],["ada",1400,300],["bob",1500,6000]]
Output: [null,"primary","primary","replica","replica","primary"]
Explanation: Ada's write at 1000 isn't on the replica at 1100 (it has data up to 800); Bob never wrote; at 1400 the replica has data up to 1100; at 1500 the replica is 6 s behind, beyond the 5 s limit.

Hints

Hint 1

Track the latest write time per user.

Hint 2

The replica contains a write made at time t if t ≤ nowMs − replicaLagMs.

Write and run your solution

Loading the editor… (JavaScript is required to run code in your browser.)

Solution and explanation

Show the solution

Time O(1) per call · Space O(users)

Keep the latest write time (in production: the primary's WAL position after the write) per user. A replica that is lag behind has applied everything up to now − lag; if the user's latest write is newer than that, reading from the replica could show stale data, so route to the primary. Lag beyond the limit means the replica is unhealthy for everyone. This exact check beats a fixed "sticky for N seconds" window when lag spikes.

Reference solution

class Router {
  constructor(maxLagMs) {
    this.maxLagMs = maxLagMs;
    this.lastWrite = new Map();
  }

  write(user, nowMs) {
    this.lastWrite.set(user, nowMs);
    return "primary";
  }

  read(user, nowMs, replicaLagMs) {
    if (replicaLagMs > this.maxLagMs) return "primary";
    const last = this.lastWrite.get(user);
    if (last !== undefined && last > nowMs - replicaLagMs) return "primary";
    return "replica";
  }
}

Common mistakes

  • Comparing with ≥ instead of > at the boundary.
  • Forgetting users who never wrote can always use a healthy replica.
  • Ignoring an unhealthy replica.

Follow-up questions

  • Store positions server-side so read-your-writes works across devices.
  • Add monotonic reads: remember the newest position each user has seen.