Distributed Locks skill for Codex

Leases, fencing tokens, or no lock at all. Codex first asks whether duplicate work is wasteful or corrupting, then reaches for the lightest fix: a unique constraint, optimistic versioning, SKIP LOCKED or partitioning. When a lock is warranted it uses token-checked leases for efficiency and fencing tokens checked by the resource for correctness, avoids Redlock and session advisory locks behind PgBouncer, and proves behaviour with concurrency and lease-expiry tests.

  • Architecture
  • $distributed-locks
  • 160 lines
  • 2 files
  • ~1,900 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- distributed-locks

Installs to ~/.agents/skills/distributed-locks/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $distributed-locks, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Decides whether a distributed lock is needed at all, and if so implements it safely with leases, owner tokens and fencing tokens on Redis, PostgreSQL advisory locks, etcd, ZooKeeper, DynamoDB conditional writes or Kubernetes Lease leader election - or replaces it with unique constraints, optimistic concurrency, SKIP LOCKED queues or partitioning. Use when two workers process the same job, a cron runs twice across replicas, someone proposes Redlock, a lock expires mid-task, or leader election is needed.

Use it when

  • Two workers or replicas process the same job or cron
  • Someone proposes a Redis or Redlock lock for correctness
  • A lease expires mid-task and work overlaps
  • A service needs leader election

Use something else when

How to check the result

A test with ten or more concurrent workers shows the protected action happens once, and a paused holder whose lease expired has its late write rejected by the fence.

The mistake it prevents

Treating a Redis lease as a correctness guarantee, when a GC pause or network stall lets two holders act at once unless the resource checks a fencing token.

~/.agents/skills/distributed-locks/SKILL.md

--- name: distributed-locks description: Decides whether a distributed lock is needed at all, and if so implements it safely with leases, owner tokens and fencing tokens on Redis, PostgreSQL… license: MIT ---

Done well means the team knows which kind of lock it has: an efficiency lock (duplicate work is wasteful but harmless) or a correctness lock (duplicate work corrupts data). An efficiency lock can be a simple lease. A correctness lock needs a fencing token checked by the resource being protected, because any lease can expire while its holder is paused. Often the best lock is none: a database constraint or conditional write does the job.

Before adding a lock

  1. Read AGENTS.md and existing coordination code: rg -n "advisory_lock|SETNX|NX.*PX|Redlock|redlock|\.lock\(|Lease|leaderelection|SKIP LOCKED" src.
  2. Write the failure scenario in one sentence: “Two pods run the nightly invoice job and customers get billed twice.” That sentence decides everything below.
  3. Identify the protected resource (a row, a file, an external API) and whether it can check a token or condition itself.

Do you need a lock?

ProblemBetter than a lock
Prevent duplicate rows (two signups, two charges for one order)Unique constraint or idempotency key; handle the conflict
Lost updates on the same rowOptimistic concurrency: UPDATE ... SET version = version + 1 WHERE id = $1 AND version = $2, retry on 0 rows
Many workers pulling jobs from a tableSELECT ... FOR UPDATE SKIP LOCKED LIMIT n inside a transaction
All events for one entity must be processed in order by one workerPartition the queue or stream by entity id (Kafka key, SQS FIFO group id)
Counter or balance changesAtomic increments or conditional writes in the store itself
Exactly one scheduler instanceLeader election with a lease, or a platform scheduler (Kubernetes CronJob with concurrencyPolicy: Forbid)

Use a distributed lock only when the work spans systems that cannot express the condition themselves and serialisation is truly required.

Lock types and where to get them

NeedRecommendedFencing token available
Efficiency lock, Redis already in the stackRedis SET key token NX PX ttl with compare-and-delete release (or the client library’s lock)No (not safely)
Lock around work inside one Postgres databaseTransaction-scoped advisory lock pg_try_advisory_xact_lockThe transaction itself is the boundary
Correctness lock across servicesetcd or ZooKeeper (consensus-backed)Yes: the lock key’s revision or the znode’s version
AWS-native, no extra infrastructureDynamoDB conditional writes on a lock item with lease expiry and a counterYes, if you increment a counter attribute
Leader election in Kubernetescoordination.k8s.io Lease via client-go leaderelection or controller-runtimeLease transitions count; still pair with fencing for external writes

Redlock (locking across several independent Redis nodes) does not provide fencing and relies on timing assumptions; do not use it as a correctness lock. If someone proposes it, ask which failure the lock must prevent and route to the table above.

Implementations

Redis lease (efficiency only)

from redis.exceptions import LockError

lock = redis_client.lock("lock:report:2026-10-28", timeout=60)  # redis-py Lock
if not lock.acquire(blocking=False):
    return  # someone else is doing it
try:
    build_report()          # must finish well within 60 s, or extend the lease
finally:
    try:
        lock.release()      # token-checked release; raises if the lease was lost
    except LockError:
        log.warning("lease expired before release; work may have overlapped")

Hand-rolled equivalent: acquire with SET lock:x <random-token> NX PX 60000, release with a Lua script that deletes only if the stored value equals your token:

if redis.call("GET", KEYS[1]) == ARGV[1] then
  return redis.call("DEL", KEYS[1])
end
return 0

Never release with a plain DEL: if your lease expired and another worker acquired the lock, you delete their lock.

Postgres advisory lock

BEGIN;
SELECT pg_try_advisory_xact_lock(hashtextextended('invoice-run:2026-10', 0)) AS got;
-- if got is false: ROLLBACK and exit
-- do the work in this same transaction; the lock releases on COMMIT or ROLLBACK
COMMIT;

Prefer the _xact_ variants. Session-level advisory locks leak when a pooled connection is returned without unlocking, and they do not work through PgBouncer in transaction pooling mode because consecutive statements may run on different server connections.

Fencing tokens (correctness)

  1. Acquire the lock from a store that returns a monotonically increasing number with each grant (etcd revision, ZooKeeper zxid or version, a DynamoDB counter attribute updated in the same conditional write).
  2. Pass the token with every write to the protected resource.
  3. The resource rejects writes carrying a token lower than the highest it has seen:
UPDATE ledgers
SET balance = $1, fence = $2
WHERE id = $3 AND fence < $2;   -- 0 rows updated means a newer holder exists: abort

If the resource cannot check a token (a third-party API), you cannot get correctness from a lock alone; use idempotency keys on that API instead.

Leases and long work

  • Lease TTL must exceed the worst-case pause (GC, VM stall, network partition) plus work time, or the holder must renew. Renew at about one third of the TTL and stop working immediately if renewal fails.
  • Check the lease (or carry the fence) before each side effect in long jobs, not only at the start.

Gotchas

  • Clock assumptions: lease expiry measured on different machines drifts; a paused process does not know its lease expired. This is why fencing exists.
  • Holding a lock across a network call to a slow dependency turns the dependency’s latency into contention for everyone.
  • Lock keys built from user input without normalisation (case, whitespace) let two “different” keys protect the same resource.
  • hashtext on lock names can collide; use hashtextextended (64-bit) or a lookup table of integer lock ids for important locks.
  • Cron jobs on every replica plus a lock is fragile; a single scheduler (CronJob, cloud scheduler) plus idempotent jobs is simpler.
  • Deleting lock keys or terminating backends that hold advisory locks in production to “unstick” a job can cause the duplicate work the lock prevented; confirm with the user that the holder is truly dead before forcing a release.

Verification

  • Concurrency test: start N workers (threads or processes, N of at least 10) against a real Redis or Postgres in a container and assert the protected action ran exactly once, or that duplicates were rejected by the constraint or fence.
  • Expiry test: make the holder sleep past its TTL, let a second worker acquire, then let the first resume. With fencing, the first worker’s write must be rejected. Without fencing, document that overlap is possible and harmless (efficiency lock).
  • Release test: the token-checked release must not delete another holder’s lock.

Output template

## Coordination design: <operation>
**Failure being prevented:** <one sentence>
**Lock type:** efficiency | correctness
**Mechanism:** <constraint / optimistic version / SKIP LOCKED / lease + fence / leader election>
**Store:** <Redis / Postgres / etcd / DynamoDB / Kubernetes Lease>
**TTL and renewal:** <values, renewal interval, behaviour on renewal failure>
**Fencing:** <token source, where it is checked>, or "not needed because ..."
**Tests:** <concurrency, expiry, release tests and results>

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Distributed Locks"
  short_description: "Leases, fencing tokens, or no lock at all"
  default_prompt: "$distributed-locks Our nightly billing job sometimes runs twice across pods, make it run exactly once"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem