Introduction
Multiple servers accidentally processing the same job — use Redis Redlock to implement distributed locks and ensure exclusive access to critical sections. Let Claude Code design the solution.
CLAUDE.md Rules
## Distributed Lock Rules
- Redis: must use odd number (3+)
- Lock TTL: 2x expected processing time
- Acquisition timeout: < 100ms
- Deadlock: auto-release via TTL
- Release: verify lock ID before releasing
Generated Implementation
// src/lock/distributedLock.ts
const redlock = new Redlock(redisClients, {
driftFactor: 0.01,
retryCount: 3,
retryDelay: 200,
retryJitter: 100,
});
export class DistributedLock {
// Exclusive lock with guaranteed release
static async withLock<T>(resource: string, ttlMs: number, fn: () => Promise<T>): Promise<T> {
const lock = await redlock.acquire([`lock:${resource}`], ttlMs);
try {
return await fn();
} finally {
await lock.release().catch(() => {}); // TTL auto-releases on failure
}
}
// Try lock, skip if already locked (batch job dedup)
static async tryWithLock<T>(resource: string, ttlMs: number, fn: () => Promise<T>) {
try {
const lock = await redlock.acquire([`lock:${resource}`], ttlMs, { retryCount: 0 });
try { return { executed: true, result: await fn() }; }
finally { await lock.release().catch(() => {}); }
} catch (err) {
if (err instanceof Redlock.ResourceLockedError) return { executed: false };
throw err;
}
}
}
// Coupon redemption: prevent double-use
export async function redeemCoupon(couponCode: string, userId: string) {
await DistributedLock.withLock(`coupon:${couponCode}`, 5_000, async () => {
const coupon = await prisma.coupon.findUniqueOrThrow({ where: { code: couponCode } });
if (coupon.usedAt) throw new ConflictError('Coupon already used');
await prisma.coupon.update({ where: { id: coupon.id }, data: { usedAt: new Date(), usedBy: userId } });
});
}
// Batch job: skip if another instance is running
export async function processDailyReport() {
const { executed } = await DistributedLock.tryWithLock(`daily-report:${today}`, 10*60*1000, async () => {
await generateAndSendDailyReport();
});
if (!executed) logger.info('Already running, skipping');
}
Summary
- Redlock with 3 Redis instances: majority quorum for lock validity
- TTL as deadlock safety net — even if process crashes
- tryWithLock pattern for batch job deduplication
- ExtendableLock: auto-extend TTL for long-running processes
Review with **Code Review Pack (\u00a5980)* at prompt-works.jp*
myouga (@myougatheaxo) — Axolotl VTuber.
Top comments (0)