UNPKG

@socketsecurity/lib

Version:

Core utilities and infrastructure for Socket.dev security tools

141 lines (140 loc) 4.56 kB
/** * Lock acquisition options. */ export interface ProcessLockOptions { /** * Maximum number of retry attempts. * @default 3 */ retries?: number | undefined; /** * Base delay between retries in milliseconds. * @default 100 */ baseDelayMs?: number | undefined; /** * Maximum delay between retries in milliseconds. * @default 1000 */ maxDelayMs?: number | undefined; /** * Stale lock timeout in milliseconds. * Locks older than this are considered abandoned and can be reclaimed. * Aligned with npm's npx locking strategy (5 seconds). * @default 5000 (5 seconds) */ staleMs?: number | undefined; /** * Interval for touching lock file to keep it fresh in milliseconds. * Set to 0 to disable periodic touching. * @default 2000 (2 seconds) */ touchIntervalMs?: number | undefined; } /** * Process lock manager with stale detection and exit cleanup. * Provides cross-platform inter-process synchronization using file-system * based locks. */ declare class ProcessLockManager { private activeLocks; private touchTimers; private exitHandlerRegistered; /** * Ensure process exit handler is registered for cleanup. * Registers a handler that cleans up all active locks when the process exits. */ private ensureExitHandler; /** * Touch a lock file to update its mtime. * This prevents the lock from being detected as stale during long operations. * * @param lockPath - Path to the lock directory */ private touchLock; /** * Start periodic touching of a lock file. * Aligned with npm npx strategy to prevent false stale detection. * * @param lockPath - Path to the lock directory * @param intervalMs - Touch interval in milliseconds */ private startTouchTimer; /** * Stop periodic touching of a lock file. * * @param lockPath - Path to the lock directory */ private stopTouchTimer; /** * Check if a lock is stale based on mtime. * Uses second-level granularity to avoid APFS floating-point precision issues. * Aligned with npm's npx locking strategy. * * @param lockPath - Path to the lock directory * @param staleMs - Stale timeout in milliseconds * @returns True if lock exists and is stale */ private isStale; /** * Acquire a lock using mkdir for atomic operation. * Handles stale locks and includes exit cleanup. * * This method attempts to create a lock directory atomically. If the lock * already exists, it checks if it's stale and removes it before retrying. * Uses exponential backoff with jitter for retry attempts. * * @param lockPath - Path to the lock directory * @param options - Lock acquisition options * @returns Release function to unlock * @throws Error if lock cannot be acquired after all retries * * @example * ```typescript * const release = await processLock.acquire('/tmp/my-lock') * try { * // Critical section * } finally { * release() * } * ``` */ acquire(lockPath: string, options?: ProcessLockOptions): Promise<() => void>; /** * Release a lock and remove from tracking. * Stops periodic touching and removes the lock directory. * * @param lockPath - Path to the lock directory * * @example * ```typescript * processLock.release('/tmp/my-lock') * ``` */ release(lockPath: string): void; /** * Execute a function with exclusive lock protection. * Automatically handles lock acquisition, execution, and cleanup. * * This is the recommended way to use process locks, as it guarantees * cleanup even if the callback throws an error. * * @param lockPath - Path to the lock directory * @param fn - Function to execute while holding the lock * @param options - Lock acquisition options * @returns Result of the callback function * @throws Error from callback or lock acquisition failure * * @example * ```typescript * const result = await processLock.withLock('/tmp/my-lock', async () => { * // Critical section * return someValue * }) * ``` */ withLock<T>(lockPath: string, fn: () => Promise<T>, options?: ProcessLockOptions): Promise<T>; } // Export singleton instance. export declare const processLock: ProcessLockManager; export {};