Agent Wranglers

SCL-8Required

Keep locks and counters in a shared store

Keep every lock, counter and "already done" set that must hold across requests in a store all copies see. Never keep it in process memory.

How to do it

With one copy, an in-memory lock stops a coupon being redeemed twice. With three copies, each has its own lock, and the coupon goes three times. A rate limit counted in memory lets a client through as many times as there are copies. Prefer a condition in the write itself, as Make conditional writes shows. Where you need a lock, use a database advisory lock, or a key in Redis or Valkey with an expiry and a random token. Release that key only while it still holds your token. Count rate limits as Limit how often anyone can call your APIs says.

Examples

JavaScript example

import { randomUUID } from 'node:crypto';

const RELEASE_IF_OWNER = 'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end';

export async function withLock(redis, name, ttlMs, work) {
  const key = `lock:${name}`;
  const token = randomUUID();
  if (await redis.set(key, token, 'PX', ttlMs, 'NX') !== 'OK') return false;
  try {
    await work();
    return true;
  } finally {
    await redis.eval(RELEASE_IF_OWNER, 1, key, token);
  }
}

Python example

def run_once(conn, lock_id: int, work) -> bool:
    with conn.transaction():
        locked = conn.execute("SELECT pg_try_advisory_xact_lock(%s)", (lock_id,)).fetchone()[0]
        if not locked:
            return False
        work(conn)
        return True

How to check

Search the code for in-memory locks, mutexes, and module-level sets or maps that track requests. None guards work that changes data. Run two copies and send 50 parallel redemptions of one coupon. Exactly one succeeds.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/scaling/stateless-app-servers/shared-locks-and-counters">Agent Wranglers scaling playbook</a>. In code you write, add a comment next to it with the same link.