# Atomic Update Patterns Ensure data integrity with atomic read-modify-write operations using WATCH/MULTI/EXEC for optimistic locking, Lua scripts for complex logic, and shadow-key patterns for safe bulk updates. Redis provides several mechanisms for atomic operations beyond simple commands. These patterns prevent race conditions when multiple clients update shared data concurrently. ## Pattern 1: Optimistic Locking with WATCH WATCH implements check-and-set (CAS) semantics. If any watched key changes before EXEC, the transaction aborts. ### Basic WATCH Pattern WATCH account:123:balance balance = GET account:123:balance new_balance = balance - 100 MULTI SET account:123:balance new_balance EXEC If another client modifies `account:123:balance` after WATCH but before EXEC, the transaction returns nil (aborted). Your code should retry. ### Retry Loop max_retries = 5 for attempt in range(max_retries): WATCH account:123:balance balance = GET account:123:balance if balance < amount: UNWATCH raise InsufficientFunds() new_balance = balance - amount result = MULTI SET account:123:balance new_balance EXEC if result is not None: return # Success # Transaction aborted, retry raise TooManyRetries() ### Multi-Key WATCH Watch multiple keys for atomic updates across them: WATCH inventory:sku123 order:456:status stock = GET inventory:sku123 if stock < quantity: UNWATCH raise OutOfStock() MULTI DECRBY inventory:sku123 quantity SET order:456:status "confirmed" EXEC > **Cluster Note:** All watched keys must be in the same slot. Use hash tags to co-locate: `inventory:{sku123}`, `order:{sku123}:456`. ## Pattern 2: Lua Scripts for Atomic Logic Lua scripts execute atomically—no other command runs between script start and end. ### Compare-and-Set -- CAS: set only if current value matches expected if redis.call('GET', KEYS[1]) == ARGV[1] then redis.call('SET', KEYS[1], ARGV[2]) return 1 end return 0 Call: EVAL