Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Eventual consistency is not a bug — it is a deliberate engineering trade that you make when the cost of strong consistency (locking, synchronous replication, reduced write throughput) exceeds the cost of briefly serving stale data. But 'eventually consistent' is not the same as 'sometimes wrong' — the lag window has a real duration, real causes, and real consequences that you must design around. Systems that don't acknowledge the lag window ship bugs where a user creates a post and immediately sees it missing from their feed, or worse, where a payment is confirmed but the account balance projection hasn't caught up. Understanding the lag window lets you build UI patterns, retry logic, and reconciliation jobs that make eventual consistency invisible to users.
Simulating a 100ms projection lag shows the read-your-own-writes failure mode and three strategies to handle it.
package main
import (
"fmt"
"sync"
"time"
)
// Simulated store: write to "pg", async projection to "redis".
var (
pgStore = map[string]string{} // source of truth
redisStore = map[string]string{} // eventually consistent
mu sync.Mutex
)
func writePost(id, title string) {
mu.Lock()
pgStore[id] = title
mu.Unlock()
fmt.Printf("[%s] Committed to PostgreSQL: %s\n", time.Now().Format("15:04:05.000"), id)
// Async projection — 100ms simulated lag.
go func() {
time.Sleep(100 * time.Millisecond)
mu.Lock()
redisStore[id] = title
mu.Unlock()
fmt.Printf("[%s] Projection updated in Redis: %s\n", time.Now().Format("15:04:05.000"), id)
}()
}
// Strategy 1: Read from PostgreSQL immediately after write (strong read).
func readStrong(id string) (string, bool) {
mu.Lock()
defer mu.Unlock()
v, ok := pgStore[id]
return v, ok
}
// Strategy 2: Read from Redis with a client-side optimistic cache.
func readWithOptimisticCache(id, justWrittenTitle string, fromCache bool) string {
if fromCache {
return justWrittenTitle + " (from optimistic cache)"
}
mu.Lock()
defer mu.Unlock()
return redisStore[id]
}
// Strategy 3: Poll Redis until the item appears or timeout.
func readWithPolling(id string, timeout time.Duration) (string, bool) {
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
mu.Lock()
v, ok := redisStore[id]
mu.Unlock()
if ok {
return v, true
}
time.Sleep(10 * time.Millisecond)
}
return "", false
}
func main() {
writePost("p1", "Hello Eventual Consistency")
// Immediately after write — Redis hasn't caught up yet.
v, ok := readStrong("p1")
fmt.Println("Strong read (pg):", v, ok) // present immediately
// 10ms later — Redis projection not ready.
time.Sleep(10 * time.Millisecond)
fmt.Println("Redis read at 10ms:", redisStore["p1"]) // empty — lag window
// Poll strategy — waits up to 200ms.
if v, ok := readWithPolling("p1", 200*time.Millisecond); ok {
fmt.Println("Polling read:", v) // present after ~100ms
}
}go run main.go