Pessimistic vs optimistic locks
When to serialize with locks versus version checks — and the failure modes of each.
Pessimistic vs optimistic locks
Business constraint
Two agents edit the same booking row. Finance forbids lost updates. UX forbids long freezes.
Naive v0
Always SELECT FOR UPDATE. Or always blind UPDATE with no version. Or app-level mutex on one node only.
Failure drill
Pessimistic locks under contention create convoys and deadlocks. Optimistic updates silently overwrite without versions. Single-node mutex lies under multi-replica deploy.
Evolution path
Iteration 1
Classify conflicts: high contention short critical sections → pessimistic or lease; low contention → optimistic version column.
Iteration 2
Optimistic: UPDATE … WHERE id=? AND version=?; bump version; on 0 rows, reload and retry with budget.
Iteration 3
For distributed writers, add lease + fencing token (lab lease-lock) so a timed-out holder cannot write after losing the lease.
Implementation cut
Document the conflict rate you expect. Prefer optimistic for user edits; leases for exclusive workers. Never mix "TTL lock" without fencing.
Numbers
Optimistic retry rate under load tests. Lock wait p99. Lost-update incidents = 0 in soak tests with adversarial concurrency.
Pattern tags
Self-check
- What does a version column prevent?
- When do pessimistic locks win?
- What is a fencing token?
- Why is a TTL lock alone unsafe?
- How do you bound optimistic retries?
Walkthrough
Recordings will appear here when published. Until then, work the failure drill and lab locally — pause after each iteration and write the metric that moved.
Lab package: see /systems/labs/lease-lock/.