UNPKG

@shagital/atomic-lock

Version:

Universal atomic locking with pluggable drivers (Redis, SQLite, File, Memory)

140 lines (139 loc) 4.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MemoryLockDriver = void 0; /** * In-memory driver implementation (for testing and single-process scenarios) */ class MemoryLockDriver { constructor(config = {}) { this.locks = new Map(); if (config.cleanupInterval) { this.cleanupInterval = setInterval(() => { this.cleanup().catch(console.error); }, config.cleanupInterval); } } async tryAcquire(key, lockValue, expiryInSeconds) { const now = Date.now(); const existing = this.locks.get(key); // Check if existing lock is expired if (existing && existing.expiresAt < now) { this.locks.delete(key); } // Check if lock exists and is not expired if (this.locks.has(key)) { return false; } // Acquire lock this.locks.set(key, { value: lockValue, expiresAt: now + (expiryInSeconds * 1000), createdAt: now }); return true; } async tryAcquireMultiple(keys, lockValue, expiryInSeconds) { const now = Date.now(); // Clean up expired locks for all keys for (const key of keys) { const existing = this.locks.get(key); if (existing && existing.expiresAt < now) { this.locks.delete(key); } } // Check if any locks exist for (const key of keys) { if (this.locks.has(key)) { return false; } } // Acquire all locks const lockData = { value: lockValue, expiresAt: now + (expiryInSeconds * 1000), createdAt: now }; for (const key of keys) { this.locks.set(key, lockData); } return true; } async release(key, lockValue) { const existing = this.locks.get(key); if (existing && existing.value === lockValue) { this.locks.delete(key); return true; } return false; } async releaseMultiple(keys, lockValue) { let released = 0; for (const key of keys) { const success = await this.release(key, lockValue); if (success) released++; } return released; } async exists(key) { const existing = this.locks.get(key); if (!existing) return false; // Check if expired if (existing.expiresAt < Date.now()) { this.locks.delete(key); return false; } return true; } async getLockInfo(key) { const existing = this.locks.get(key); if (!existing) return null; // Check if expired if (existing.expiresAt < Date.now()) { this.locks.delete(key); return null; } return { key, value: existing.value, expiresAt: existing.expiresAt, createdAt: existing.createdAt }; } async cleanup() { const now = Date.now(); for (const [key, lock] of this.locks.entries()) { if (lock.expiresAt < now) { this.locks.delete(key); } } } async close() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } this.locks.clear(); } // For testing purposes getLockCount() { return this.locks.size; } getAllLocks() { const result = new Map(); const now = Date.now(); for (const [key, lock] of this.locks.entries()) { if (lock.expiresAt >= now) { result.set(key, { key, value: lock.value, expiresAt: lock.expiresAt, createdAt: lock.createdAt }); } } return result; } } exports.MemoryLockDriver = MemoryLockDriver;