Multi-Region Writes and Conflict Resolution
Understand when to enable multi-region writes, how Last-Writer-Wins and custom conflict resolution work, and the impact on consistency levels and application design.
When writes need to be everywhere
Imagine GlobeCart has checkout counters in 12 countries. With single-write, every sale must phone home to the one βmasterβ counter in East US. Thatβs slow and fragile β if East US goes down, nobody can buy anything.
Multi-region writes let each country process sales locally. Faster checkouts, higher availability. The catch? Two countries might sell the last item simultaneously β you need a rule to break the tie.
Jakeβs decision: single-write or multi-write?
π Jake at GlobeCart runs in 12 regions. His product catalogue is read-heavy (99% reads), so single-write works fine β read replicas handle the load. But the order processing system is write-heavy: customers place orders from everywhere simultaneously.
Jake enables multi-region writes for the orders database to get:
- Local write latency for checkout speed
- 99.999% availability SLA
- No write outage during regional failures
Single-write vs multi-write
| Aspect | Single-Write | Multi-Write |
|---|---|---|
| Write location | One designated region | Any configured region |
| Write latency | Low locally, high remotely | Low everywhere |
| Availability SLA | 99.99% | 99.999% |
| Consistency levels | All 5 available | Session, Consistent Prefix, Eventual only |
| Conflict resolution | Not needed | Required (LWW default) |
| Cost | Standard per-region RU | Higher β write RU in every region |
| Failover behaviour | Promote read region to write | No failover needed β all regions write |
| Best for | Read-heavy, simple architecture | Write-heavy, global low-latency writes |
Conflict resolution: Last-Writer-Wins (LWW)
LWW is the default conflict resolution policy. When two regions write to the same item simultaneously, the write with the highest value on the conflict resolution path wins.
Default conflict resolution path: _ts (timestamp)
Region A writes product price = $29.99 at _ts = 1000
Region B writes product price = $24.99 at _ts = 1001
Winner: Region B ($24.99) β higher _ts wins
Loser: Region A's write is discarded silently
Custom LWW path
You can use any numeric property instead of _ts:
// Use a custom numeric property for LWW
ContainerProperties properties = new ContainerProperties("orders", "/customerId")
{
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.LastWriterWins,
ResolutionPath = "/priority" // higher numeric value wins
}
};
Exam tip: LWW path must be numeric
The LWW conflict resolution path must point to a numeric property. If you specify a path that doesnβt exist or isnβt numeric, Cosmos DB falls back to _ts. The exam may test this edge case β an invalid path doesnβt throw an error; it silently uses _ts.
Custom conflict resolution (stored procedure)
For complex merge logic, register a stored procedure that runs when conflicts are detected:
ContainerProperties properties = new ContainerProperties("inventory", "/warehouseId")
{
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.Custom,
ResolutionProcedure = "dbs/globecart/colls/inventory/sprocs/mergeInventory"
}
};
The stored procedure receives both conflicting documents and must return the merged result. If the procedure fails or isnβt registered, conflicts go to the conflict feed for manual resolution.
The conflict feed
When conflicts canβt be auto-resolved (custom mode without a procedure, or procedure failure), they land in the conflict feed β a system container you can read programmatically:
FeedIterator<ConflictProperties> conflicts = container.Conflicts
.GetConflictQueryIterator<ConflictProperties>();
while (conflicts.HasMoreResults)
{
FeedResponse<ConflictProperties> response = await conflicts.ReadNextAsync();
foreach (ConflictProperties conflict in response)
{
Console.WriteLine($"Conflict on {conflict.Id}, type: {conflict.OperationType}");
}
}
Exam tip: conflict feed expiration
Conflicts in the conflict feed are retained based on the containerβs TTL setting. If you donβt process them, they expire. In LWW mode, the conflict feed is empty because conflicts are auto-resolved β only Custom mode uses the feed (when the stored procedure is missing or fails).
Impact on consistency
Enabling multi-region writes restricts your consistency options:
| Consistency Level | Available? | Why |
|---|---|---|
| Strong | β | Requires single write source for linearizability |
| Bounded Staleness | β | Requires single write source for staleness bounds |
| Session | β | Read-your-own-writes per session still works |
| Consistent Prefix | β | Write ordering within a region is preserved |
| Eventual | β | No ordering guarantees needed |
Sophieβs tip: ποΈ Sophie points out that if Jakeβs order system previously relied on Strong consistency for inventory checks, switching to multi-region writes means redesigning that flow to handle Session consistency β possibly using optimistic concurrency with ETags instead.
π¬ Video walkthrough
π¬ Video coming soon
Multi-Region Writes and Conflict Resolution β DP-420 Module 14
Multi-Region Writes and Conflict Resolution β DP-420 Module 14
~14 minFlashcards
Knowledge Check
Jake enables multi-region writes for GlobeCart's order system. Two customers in different regions update the same order simultaneously. The account uses the default conflict resolution policy. Which write wins?
Jake wants his inventory system to merge conflicting stock updates rather than picking one winner. What should he configure?
After enabling multi-region writes, Jake's team discovers their code relies on Strong consistency for critical reads. What's the impact?
Next up: Change Feed with Azure Functions and Processors β how to react to data changes in real time by streaming inserts and updates from your Cosmos DB containers.