gotchatypescriptMajor
Last-Write-Wins Conflict Resolution Silently Discards Concurrent Edits
Viewed 0 times
last write winsLWWconflict resolutionconcurrent editdata lossmerge strategyvector clock
Problem
A simple last-write-wins (LWW) strategy is used for real-time collaborative data. Users frequently lose their edits when two people modify the same field within milliseconds of each other.
Solution
Use LWW only for fields where losing an intermediate value is acceptable (e.g., cursor position, toggle state). For text and structured data, use CRDTs or merge strategies that preserve intent from all writers.
// LWW is fine for presence / cursor position
type CursorUpdate = { userId: string; x: number; y: number; timestamp: number };
function mergePositions(a: CursorUpdate, b: CursorUpdate): CursorUpdate {
return a.timestamp >= b.timestamp ? a : b; // LWW safe here
}
// For structured data, use explicit merge
type CounterUpdate = { value: number; by: string };
function mergeCounters(base: number, a: CounterUpdate, b: CounterUpdate): number {
// Preserve both increments — semantic merge
return base + (a.value - base) + (b.value - base);
}Why
Wall-clock timestamps are unreliable in distributed systems — two clients can have clocks skewed by seconds. LWW with wall-clock time will silently prefer the client with the faster clock.
Gotchas
- Use vector clocks or Lamport timestamps instead of wall-clock time for LWW if you must use it.
- Inform users when their edit was overwritten — never silently discard input without notification.
- CRDTs for counters (G-Counter, PN-Counter) handle concurrent increments correctly by design.
- For rich text, Yjs Y.Text is almost always the right answer over a custom LWW strategy.
Revisions (0)
No revisions yet.