@socketsecurity/lib
Version:
Core utilities and infrastructure for Socket.dev security tools
141 lines (140 loc) • 4.56 kB
TypeScript
/**
* 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 {};