When distributed coordination is actually needed
coreintermediateDistributed coordination — a lock held across multiple processes or machines — is needed only when the resource being protected is itself outside any single database that could enforce the invariant directly. If one Postgres instance already holds the data and can express "only one of these" as a transaction or a constraint, that is not a distributed-locking problem at all; it becomes one when multiple independent workers must serialize access to something a single ACID transaction cannot already cover — a shared external resource, a scheduled job that must run on exactly one of many replicas, or a critical section spanning several services and calls.
Think of it as
A single database transaction is like one person checking out a book from a library's own front desk — the desk itself can refuse to hand out a second copy, no extra coordination needed. A distributed lock is like several branch libraries, with no shared front desk, needing to agree by phone call that only one of them lends out the last copy of a book that physically exists in just one place. You only need the phone call when there genuinely is no single front desk that already knows the whole picture.
What we're doing: Tell apart a case that only looks like it needs a distributed lock from one that genuinely does.
- 12
- ON CONFLICT DO NOTHING is the coordination mechanism — the database resolves the race atomically, with no separate lock service in the picture.
- 15
- Exactly one concurrent INSERT wins; every other worker sees zero affected rows and knows it lost — that is the entire "lock" this scenario needed.
Why this works: This is the single most common misjudgment in practice: reaching for a distributed lock (Redis, ZooKeeper, etcd) for a problem that a shared relational database already solves with a unique constraint, because the *workers* are distributed even though the *data* is not.
Standing up a Redis-based lock for a coordination problem the existing database already covers
Wrong
Better
What you see: A postmortem where the digest was sent twice not because the Redis lock logic was wrong, but because Redis itself had a brief outage or failover unrelated to the actual business data — a dependency the design never needed to take on.
Why: Adding Redis here introduces a second system that must stay available and correctly configured for a guarantee the existing database could give for free — every new coordination service is a new thing that can be down, misconfigured, or drift out of sync with the data it is meant to protect.
- Shared invariant — multiple processes involved
- leads to One DB already owns it (yes)
- on error, leads to Spans systems (no)
- One DB already owns it — use a transaction/constraint
- Spans systems — needs a distributed lock
Deciding whether a problem needs a distributed lock
Remember: Ask "does one database already own this invariant?" before reaching for a distributed lock — if yes, use its transaction/constraint machinery; a distributed lock is for coordination that genuinely spans systems no single database transaction covers.
See also: risks of distributed locks · prefer simpler mechanisms · concurrency control mechanisms

