@nestjs-redisx/locks 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15,6 +15,9 @@ var __decorateClass = (decorators, target, key, kind) => {
15
15
  };
16
16
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
17
17
 
18
+ // package.json
19
+ var version = "1.0.3";
20
+
18
21
  // src/shared/constants/index.ts
19
22
  var LOCKS_PLUGIN_OPTIONS = /* @__PURE__ */ Symbol.for("LOCKS_PLUGIN_OPTIONS");
20
23
  var LOCK_SERVICE = /* @__PURE__ */ Symbol.for("LOCK_SERVICE");
@@ -579,7 +582,7 @@ var LocksPlugin = class _LocksPlugin {
579
582
  this.options = options;
580
583
  }
581
584
  name = "locks";
582
- version = "0.1.0";
585
+ version = version;
583
586
  description = "Distributed locking with auto-renewal and retry strategies";
584
587
  asyncOptions;
585
588
  static registerAsync(asyncOptions) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/lock/api/decorators/with-lock.decorator.ts","../src/lock/application/services/lock-decorator-initializer.service.ts","../src/lock/domain/entities/lock.entity.ts","../src/lock/application/services/lock.service.ts","../src/lock/infrastructure/scripts/lua-scripts.ts","../src/lock/infrastructure/adapters/redis-lock-store.adapter.ts","../src/locks.plugin.ts"],"names":["RedisXError","ErrorCode","Logger","Injectable","LockService","Inject","Optional","REDIS_DRIVER","Reflector"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Injection token for locks plugin options\n */\nexport const LOCKS_PLUGIN_OPTIONS = Symbol.for('LOCKS_PLUGIN_OPTIONS');\n\n/**\n * Injection token for lock service\n */\nexport const LOCK_SERVICE = Symbol.for('LOCK_SERVICE');\n\n/**\n * Injection token for lock store\n */\nexport const LOCK_STORE = Symbol.for('LOCK_STORE');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\n/**\n * Base error class for all lock-related errors.\n */\nexport class LockError extends RedisXError {\n constructor(\n message: string,\n code: ErrorCode,\n public readonly lockKey: string,\n cause?: Error,\n ) {\n super(message, code, cause, { lockKey });\n }\n}\n\n/**\n * Error thrown when lock acquisition fails.\n */\nexport class LockAcquisitionError extends LockError {\n constructor(\n key: string,\n public readonly reason: 'timeout' | 'held' | 'error',\n cause?: Error,\n ) {\n super(`Failed to acquire lock \"${key}\": ${reason}`, reason === 'timeout' ? ErrorCode.LOCK_ACQUISITION_TIMEOUT : ErrorCode.LOCK_ACQUISITION_FAILED, key, cause);\n }\n}\n\n/**\n * Error thrown when attempting to release or extend a lock not owned by the caller.\n */\nexport class LockNotOwnedError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n ) {\n super(`Lock \"${key}\" not owned by token \"${token}\"`, ErrorCode.LOCK_NOT_OWNED, key);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when lock extension fails.\n */\nexport class LockExtensionError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n cause?: Error,\n ) {\n super(`Failed to extend lock \"${key}\"`, ErrorCode.LOCK_EXTENSION_FAILED, key, cause);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when a lock has expired.\n */\nexport class LockExpiredError extends LockError {\n constructor(key: string) {\n super(`Lock \"${key}\" expired`, ErrorCode.LOCK_EXPIRED, key);\n }\n}\n","/**\n * @WithLock decorator for distributed locking.\n *\n * Uses immediate proxy-based wrapping (not deferred to interceptor).\n * Works on ANY Injectable class methods (services, repositories, etc).\n */\n\nimport { Logger } from '@nestjs/common';\nimport 'reflect-metadata';\nimport { LockAcquisitionError } from '../../../shared/errors';\n\nconst logger = new Logger('WithLock');\n\n/**\n * Metadata key for @WithLock decorator options.\n */\nexport const WITH_LOCK_OPTIONS = Symbol.for('WITH_LOCK_OPTIONS');\n\n/**\n * Lock interface for decorator use.\n */\ninterface IDecoratorLock {\n release(): Promise<void>;\n}\n\n/**\n * Lock service interface for decorator use.\n */\ninterface IDecoratorLockService {\n acquire(\n key: string,\n options?: {\n ttl?: number;\n waitTimeout?: number;\n autoRenew?: boolean;\n },\n ): Promise<IDecoratorLock>;\n}\n\n// Global service getter for lazy injection\nlet globalLockServiceGetter: (() => IDecoratorLockService) | null = null;\n\n/**\n * Register lock service getter for lazy injection.\n * Called by LocksPlugin during initialization.\n */\nexport function registerLockServiceGetter(getter: () => IDecoratorLockService): void {\n globalLockServiceGetter = getter;\n}\n\n/**\n * Options for @WithLock decorator.\n */\nexport interface IWithLockOptions {\n /**\n * Lock key or key builder function.\n *\n * @example\n * ```typescript\n * @WithLock({ key: 'update-user:{0}' }) // Uses first argument\n * @WithLock({ key: (dto) => `order:${dto.id}` }) // Custom function\n * ```\n */\n key: string | ((...args: unknown[]) => string);\n\n /**\n * Lock TTL in milliseconds.\n */\n ttl?: number;\n\n /**\n * Maximum time to wait for lock acquisition in milliseconds.\n */\n waitTimeout?: number;\n\n /**\n * Enable auto-renewal.\n */\n autoRenew?: boolean;\n\n /**\n * Action to take if lock acquisition fails.\n * - 'throw': Throw LockAcquisitionError (default)\n * - 'skip': Skip method execution and return undefined\n * - function: Throw custom error\n */\n onLockFailed?: 'throw' | 'skip' | ((key: string) => Error);\n}\n\n/**\n * Decorator for distributed locking.\n *\n * Acquires a distributed lock before executing the method\n * and automatically releases it afterwards.\n *\n * Works on any Injectable class method, not just controllers.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class OrderService {\n * @WithLock({ key: 'order:{0}' })\n * async processOrder(orderId: string) {\n * // Only one instance processes this order at a time\n * }\n *\n * @WithLock({\n * key: (dto) => `customer:${dto.customerId}`,\n * ttl: 60000,\n * autoRenew: true,\n * })\n * async createOrder(dto: CreateOrderDto) {\n * // Lock by customer ID with auto-renewal\n * }\n *\n * @WithLock({\n * key: 'sync:inventory',\n * onLockFailed: 'skip',\n * })\n * async syncInventory() {\n * // Will skip if already syncing\n * }\n * }\n * ```\n */\nexport function WithLock(options: IWithLockOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value as (...args: unknown[]) => Promise<unknown>;\n\n // Replace method with locking proxy\n descriptor.value = async function (...args: unknown[]): Promise<unknown> {\n // Lazy inject lock service on first call\n if (!globalLockServiceGetter) {\n logger.warn(`@WithLock: LockService not yet available, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n const lockService = globalLockServiceGetter();\n if (!lockService) {\n logger.warn(`@WithLock: LockService getter returned null, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n // Build lock key\n const key = buildLockKey(args, options);\n let lock: IDecoratorLock | null = null;\n\n try {\n // Acquire lock\n lock = await lockService.acquire(key, {\n ttl: options.ttl,\n waitTimeout: options.waitTimeout,\n autoRenew: options.autoRenew,\n });\n\n // Execute original method\n const result = await originalMethod.apply(this, args);\n\n return result;\n } catch (error) {\n // Handle lock acquisition failure\n if (error instanceof LockAcquisitionError) {\n return handleLockFailed(key, options, error);\n }\n throw error;\n } finally {\n // Always release lock\n if (lock) {\n await lock.release().catch((err: Error) => {\n logger.error(`@WithLock: Failed to release lock ${key}:`, err);\n });\n }\n }\n };\n\n // Preserve original method name\n Object.defineProperty(descriptor.value, 'name', {\n value: originalMethod.name,\n writable: false,\n });\n\n // Store metadata on WRAPPER function for reflection (after replacement)\n Reflect.defineMetadata(WITH_LOCK_OPTIONS, options, descriptor.value);\n\n return descriptor;\n };\n}\n\n/**\n * Builds lock key from template or function.\n */\nfunction buildLockKey(args: unknown[], options: IWithLockOptions): string {\n if (typeof options.key === 'function') {\n return options.key(...args);\n }\n return interpolateKey(options.key, args);\n}\n\n/**\n * Interpolates key template with arguments.\n *\n * Supports:\n * - {0}, {1}, etc. for positional arguments\n * - {0.id}, {1.name}, etc. for object properties\n */\nfunction interpolateKey(template: string, args: unknown[]): string {\n return template.replace(/\\{(\\d+)(?:\\.(\\w+))?\\}/g, (_, index, prop) => {\n const arg = args[Number(index)];\n if (prop && typeof arg === 'object' && arg !== null) {\n return String((arg as Record<string, unknown>)[prop]);\n }\n return String(arg);\n });\n}\n\n/**\n * Handles lock acquisition failure.\n */\nfunction handleLockFailed(key: string, options: IWithLockOptions, error: LockAcquisitionError): undefined {\n const handler = options.onLockFailed ?? 'throw';\n\n if (handler === 'throw') {\n throw error;\n }\n\n if (handler === 'skip') {\n return undefined;\n }\n\n if (typeof handler === 'function') {\n throw handler(key);\n }\n\n throw error;\n}\n","/**\n * Service for initializing @WithLock decorator with lazy lock service injection.\n *\n * Runs on module initialization and registers a getter function that provides\n * access to LockService for the @WithLock decorator's proxy logic.\n */\n\nimport { Injectable, OnModuleInit, Inject, Logger } from '@nestjs/common';\n\nimport { LOCK_SERVICE } from '../../../shared/constants';\nimport { registerLockServiceGetter } from '../../api/decorators/with-lock.decorator';\nimport { ILockService } from '../ports/lock-service.port';\n\n@Injectable()\nexport class LockDecoratorInitializerService implements OnModuleInit {\n private readonly logger = new Logger(LockDecoratorInitializerService.name);\n\n constructor(@Inject(LOCK_SERVICE) private readonly lockService: ILockService) {}\n\n /**\n * Called after all modules are initialized.\n * Registers lock service getter for @WithLock decorator.\n */\n // eslint-disable-next-line @typescript-eslint/require-await\n async onModuleInit(): Promise<void> {\n this.logger.debug('Registering LockService getter for @WithLock decorator');\n\n // Register getter that provides lock service to decorator\n registerLockServiceGetter(() => this.lockService);\n\n this.logger.log('@WithLock decorator initialized and ready to use');\n }\n}\n","import { LockNotOwnedError, LockExtensionError } from '../../../shared/errors';\nimport { ILockStore } from '../../application/ports/lock-store.port';\n\n/**\n * Represents an acquired distributed lock.\n */\nexport interface ILock {\n /** Lock key */\n readonly key: string;\n\n /** Unique token identifying lock ownership */\n readonly token: string;\n\n /** Lock TTL in milliseconds */\n readonly ttl: number;\n\n /** Timestamp when lock was acquired */\n readonly acquiredAt: Date;\n\n /** Timestamp when lock will expire */\n readonly expiresAt: Date;\n\n /** Whether auto-renewal is active */\n readonly isAutoRenewing: boolean;\n\n /**\n * Releases the lock.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n release(): Promise<void>;\n\n /**\n * Extends lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails\n */\n extend(ttl: number): Promise<void>;\n\n /**\n * Checks if lock is still held.\n *\n * @returns True if lock is held by this token\n */\n isHeld(): Promise<boolean>;\n\n /**\n * Stops automatic lock renewal.\n */\n stopAutoRenew(): void;\n}\n\n/**\n * Lock entity implementation.\n *\n * Represents a distributed lock with automatic renewal capability.\n * The lock maintains ownership through a unique token and can be\n * extended or released explicitly.\n *\n * @example\n * ```typescript\n * const lock = new Lock('my-resource', 'token-123', 30000, store);\n *\n * // Start auto-renewal every 15 seconds\n * lock.startAutoRenew(15000);\n *\n * try {\n * // Do work...\n * await performOperation();\n * } finally {\n * await lock.release();\n * }\n * ```\n */\nexport class Lock implements ILock {\n readonly key: string;\n readonly token: string;\n readonly ttl: number;\n readonly acquiredAt: Date;\n\n private _expiresAt: Date;\n private autoRenewTimer: NodeJS.Timeout | null = null;\n private released = false;\n\n /**\n * Creates a new Lock instance.\n *\n * @param key - Lock key in Redis\n * @param token - Unique ownership token\n * @param ttl - Time-to-live in milliseconds\n * @param store - Lock store for persistence operations\n */\n constructor(\n key: string,\n token: string,\n ttl: number,\n private readonly store: ILockStore,\n ) {\n this.key = key;\n this.token = token;\n this.ttl = ttl;\n this.acquiredAt = new Date();\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Gets the expiration timestamp.\n */\n get expiresAt(): Date {\n return this._expiresAt;\n }\n\n /**\n * Checks if auto-renewal is active.\n */\n get isAutoRenewing(): boolean {\n return this.autoRenewTimer !== null;\n }\n\n /**\n * Releases the lock.\n *\n * Stops auto-renewal and removes the lock from Redis.\n * Idempotent - can be called multiple times safely.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n async release(): Promise<void> {\n if (this.released) {\n return;\n }\n\n this.stopAutoRenew();\n\n const success = await this.store.release(this.key, this.token);\n if (!success) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n this.released = true;\n }\n\n /**\n * Extends the lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails (lock expired or not owned)\n */\n async extend(ttl: number): Promise<void> {\n if (this.released) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n const success = await this.store.extend(this.key, this.token, ttl);\n if (!success) {\n throw new LockExtensionError(this.key, this.token);\n }\n\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Checks if lock is still held.\n *\n * @returns False if released, otherwise checks Redis\n */\n async isHeld(): Promise<boolean> {\n if (this.released) {\n return false;\n }\n return this.store.isHeldBy(this.key, this.token);\n }\n\n /**\n * Starts automatic lock renewal.\n *\n * The lock will be extended at the specified interval\n * until stopAutoRenew() is called or extension fails.\n *\n * @param intervalMs - Renewal interval in milliseconds\n */\n startAutoRenew(intervalMs: number): void {\n if (this.autoRenewTimer) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.autoRenewTimer = setInterval(async () => {\n try {\n await this.extend(this.ttl);\n } catch {\n // Extension failed, stop renewing\n this.stopAutoRenew();\n }\n }, intervalMs);\n\n // Don't prevent Node.js process from exiting\n if (this.autoRenewTimer.unref) {\n this.autoRenewTimer.unref();\n }\n }\n\n /**\n * Stops automatic lock renewal.\n *\n * Safe to call multiple times.\n */\n stopAutoRenew(): void {\n if (this.autoRenewTimer) {\n clearInterval(this.autoRenewTimer);\n this.autoRenewTimer = null;\n }\n }\n}\n","import { Injectable, Inject, Logger, OnModuleDestroy, Optional } from '@nestjs/common';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_STORE } from '../../../shared/constants';\nimport { LockAcquisitionError } from '../../../shared/errors';\nimport { ILocksPluginOptions, ILockOptions } from '../../../shared/types';\nimport { Lock, ILock } from '../../domain/entities/lock.entity';\nimport { ILockService } from '../ports/lock-service.port';\nimport { ILockStore } from '../ports/lock-store.port';\n\n// Optional metrics integration\nconst METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\n\ninterface IMetricsService {\n incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void;\n setGauge(name: string, value: number, labels?: Record<string, string>): void;\n incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n}\n\n// Optional tracing integration\nconst TRACING_SERVICE = Symbol.for('TRACING_SERVICE');\n\ninterface ISpan {\n setAttribute(key: string, value: unknown): this;\n addEvent(name: string, attributes?: Record<string, unknown>): this;\n setStatus(status: 'OK' | 'ERROR'): this;\n recordException(error: Error): this;\n end(): void;\n}\n\ninterface ITracingService {\n startSpan(name: string, options?: { kind?: string; attributes?: Record<string, unknown> }): ISpan;\n}\n\n/**\n * Lock service implementation.\n *\n * Provides distributed locking with automatic retry, timeout, and renewal.\n * Implements graceful shutdown to release all active locks on module destroy.\n */\n@Injectable()\nexport class LockService implements ILockService, OnModuleDestroy {\n private readonly logger = new Logger(LockService.name);\n private readonly activeLocks = new Set<Lock>();\n\n constructor(\n @Inject(LOCKS_PLUGIN_OPTIONS) private readonly config: ILocksPluginOptions,\n @Inject(LOCK_STORE) private readonly store: ILockStore,\n @Optional() @Inject(METRICS_SERVICE) private readonly metrics?: IMetricsService,\n @Optional() @Inject(TRACING_SERVICE) private readonly tracing?: ITracingService,\n ) {}\n\n /**\n * Lifecycle hook: releases all active locks on shutdown.\n */\n async onModuleDestroy(): Promise<void> {\n // Release all active locks on graceful shutdown\n const releasePromises = Array.from(this.activeLocks).map((lock) =>\n lock.release().catch((error) => {\n // Log but don't throw - we're shutting down\n this.logger.error(`Failed to release lock ${lock.key} during shutdown:`, error);\n }),\n );\n\n await Promise.all(releasePromises);\n this.activeLocks.clear();\n }\n\n /**\n * Acquires lock with exponential backoff retry.\n */\n async acquire(key: string, options: ILockOptions = {}): Promise<ILock> {\n const span = this.tracing?.startSpan('lock.acquire', {\n kind: 'INTERNAL',\n attributes: { 'lock.key': key, 'lock.ttl': options.ttl },\n });\n\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const retry = this.resolveRetryConfig(options);\n const startTime = Date.now();\n\n let delay = retry.initialDelay;\n\n try {\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (acquired) {\n const waitDuration = (Date.now() - startTime) / 1000;\n this.metrics?.observeHistogram('redisx_lock_wait_duration_seconds', waitDuration);\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n span?.setAttribute('lock.acquired', true);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('OK');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n // Last attempt failed\n if (attempt === retry.maxRetries) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n span?.setAttribute('lock.acquired', false);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('ERROR');\n throw new LockAcquisitionError(key, 'timeout');\n }\n\n // Wait before retry\n await this.sleep(delay);\n delay = Math.min(delay * retry.multiplier, retry.maxDelay);\n }\n\n // Should never reach here, but satisfy TypeScript\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n throw new LockAcquisitionError(key, 'timeout');\n } catch (error) {\n span?.recordException(error as Error);\n span?.setStatus('ERROR');\n throw error;\n } finally {\n span?.end();\n }\n }\n\n /**\n * Tries to acquire lock once without retry.\n */\n async tryAcquire(key: string, options: ILockOptions = {}): Promise<ILock | null> {\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (!acquired) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n return null;\n }\n\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n /**\n * Executes function with automatic lock management.\n */\n async withLock<T>(key: string, fn: () => Promise<T>, options: ILockOptions = {}): Promise<T> {\n const lock = await this.acquire(key, options);\n const holdStart = Date.now();\n\n try {\n return await fn();\n } finally {\n const holdDuration = (Date.now() - holdStart) / 1000;\n this.metrics?.observeHistogram('redisx_lock_hold_duration_seconds', holdDuration);\n this.metrics?.decrementGauge('redisx_locks_active');\n\n await lock\n .release()\n .catch((error) => {\n this.logger.error(`Lock release failed for ${key}:`, error);\n })\n .finally(() => {\n this.activeLocks.delete(lock as Lock);\n });\n }\n }\n\n /**\n * Checks if key is locked.\n */\n async isLocked(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.exists(fullKey);\n }\n\n /**\n * Force releases lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.forceRelease(fullKey);\n }\n\n /**\n * Creates lock instance with optional auto-renewal.\n */\n private createLock(fullKey: string, token: string, ttl: number, options: ILockOptions): Lock {\n const lock = new Lock(fullKey, token, ttl, this.store);\n\n // Setup auto-renew if enabled\n const autoRenewEnabled = options.autoRenew ?? this.config.autoRenew?.enabled ?? true;\n if (autoRenewEnabled) {\n const intervalFraction = this.config.autoRenew?.intervalFraction ?? 0.5;\n const interval = ttl * intervalFraction;\n lock.startAutoRenew(interval);\n }\n\n return lock;\n }\n\n /**\n * Builds full lock key with prefix.\n */\n private buildKey(key: string): string {\n const prefix = this.config.keyPrefix ?? '_lock:';\n return `${prefix}${key}`;\n }\n\n /**\n * Generates unique lock token.\n */\n private generateToken(): string {\n return `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n }\n\n /**\n * Resolves TTL with defaults and limits.\n */\n private resolveTtl(ttl?: number): number {\n const resolvedTtl = ttl ?? this.config.defaultTtl ?? 30000;\n const maxTtl = this.config.maxTtl ?? 300000;\n return Math.min(resolvedTtl, maxTtl);\n }\n\n /**\n * Resolves retry configuration.\n */\n private resolveRetryConfig(options: ILockOptions) {\n return {\n maxRetries: options.retry?.maxRetries ?? this.config.retry?.maxRetries ?? 3,\n initialDelay: options.retry?.initialDelay ?? this.config.retry?.initialDelay ?? 100,\n maxDelay: this.config.retry?.maxDelay ?? 3000,\n multiplier: this.config.retry?.multiplier ?? 2,\n };\n }\n\n /**\n * Sleeps for specified milliseconds.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Inline Lua scripts for lock operations.\n *\n * Scripts are stored as inline strings to avoid issues with file reading\n * after build (dist directory doesn't contain .lua files).\n */\n\n/**\n * Release lock if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * Returns: 1 if released, 0 if not owned or doesn't exist\n */\nexport const RELEASE_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\nelse\n return 0\nend\n`.trim();\n\n/**\n * Extend lock TTL if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * ARGV[2] = TTL in milliseconds\n * Returns: 1 if extended, 0 if not owned or doesn't exist\n */\nexport const EXTEND_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"pexpire\", KEYS[1], ARGV[2])\nelse\n return 0\nend\n`.trim();\n","import { Injectable, Inject, OnModuleInit } from '@nestjs/common';\nimport { IRedisDriver, REDIS_DRIVER } from '@nestjs-redisx/core';\n\nimport { ILockStore } from '../../application/ports/lock-store.port';\nimport { RELEASE_LOCK_SCRIPT, EXTEND_LOCK_SCRIPT } from '../scripts/lua-scripts';\n\n/**\n * Redis-based lock store implementation.\n *\n * Uses atomic Redis operations for lock management:\n * - SET NX PX for acquiring locks\n * - Lua scripts for safe release and extension\n */\n@Injectable()\nexport class RedisLockStoreAdapter implements ILockStore, OnModuleInit {\n private releaseSha: string | null = null;\n private extendSha: string | null = null;\n\n constructor(@Inject(REDIS_DRIVER) private readonly driver: IRedisDriver) {}\n\n /**\n * Lifecycle hook: loads Lua scripts into Redis on initialization.\n */\n async onModuleInit(): Promise<void> {\n // Pre-load Lua scripts and cache their SHA hashes\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n /**\n * Acquires lock using SET NX PX.\n */\n async acquire(key: string, token: string, ttlMs: number): Promise<boolean> {\n const result = await this.driver.set(key, token, {\n nx: true, // Only set if key doesn't exist\n px: ttlMs, // TTL in milliseconds\n });\n return result === 'OK';\n }\n\n /**\n * Releases lock if owned by token (Lua script).\n */\n async release(key: string, token: string): Promise<boolean> {\n if (!this.releaseSha) {\n // Fallback if script not loaded\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.releaseSha, [key], [token]);\n return result === 1;\n }\n\n /**\n * Extends lock TTL if owned by token (Lua script).\n */\n async extend(key: string, token: string, ttlMs: number): Promise<boolean> {\n if (!this.extendSha) {\n // Fallback if script not loaded\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.extendSha, [key], [token, ttlMs]);\n return result === 1;\n }\n\n /**\n * Checks if lock key exists.\n */\n async exists(key: string): Promise<boolean> {\n const count = await this.driver.exists(key);\n return count > 0;\n }\n\n /**\n * Checks if lock is held by specific token.\n */\n async isHeldBy(key: string, token: string): Promise<boolean> {\n const value = await this.driver.get(key);\n return value === token;\n }\n\n /**\n * Force removes lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const count = await this.driver.del(key);\n return count > 0;\n }\n}\n","/**\n * Locks plugin for NestJS RedisX.\n * Provides distributed locking with auto-renewal and retry strategies.\n */\n\nimport { DynamicModule, ForwardReference, Provider, Type } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IRedisXPlugin, IPluginAsyncOptions } from '@nestjs-redisx/core';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_SERVICE, LOCK_STORE } from './shared/constants';\nimport { ILocksPluginOptions } from './shared/types';\nimport { LockDecoratorInitializerService } from './lock/application/services/lock-decorator-initializer.service';\nimport { LockService } from './lock/application/services/lock.service';\nimport { RedisLockStoreAdapter } from './lock/infrastructure/adapters/redis-lock-store.adapter';\n\nconst DEFAULT_LOCKS_CONFIG: Required<Omit<ILocksPluginOptions, 'isGlobal'>> = {\n defaultTtl: 30000,\n maxTtl: 300000,\n keyPrefix: '_lock:',\n retry: {\n maxRetries: 3,\n initialDelay: 100,\n maxDelay: 3000,\n multiplier: 2,\n },\n autoRenew: {\n enabled: true,\n intervalFraction: 0.5,\n },\n};\n\n/**\n * Distributed locks plugin for NestJS RedisX.\n *\n * Provides distributed locking with auto-renewal and retry strategies.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new LocksPlugin({\n * defaultTtl: 30000,\n * keyPrefix: '_lock:',\n * autoRenew: { enabled: true },\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class LocksPlugin implements IRedisXPlugin {\n readonly name = 'locks';\n readonly version = '0.1.0';\n readonly description = 'Distributed locking with auto-renewal and retry strategies';\n\n private asyncOptions?: IPluginAsyncOptions<ILocksPluginOptions>;\n\n constructor(private readonly options: ILocksPluginOptions = {}) {}\n\n static registerAsync(asyncOptions: IPluginAsyncOptions<ILocksPluginOptions>): LocksPlugin {\n const plugin = new LocksPlugin();\n plugin.asyncOptions = asyncOptions;\n return plugin;\n }\n\n private static mergeDefaults(options: ILocksPluginOptions): ILocksPluginOptions {\n return {\n defaultTtl: options.defaultTtl ?? DEFAULT_LOCKS_CONFIG.defaultTtl,\n maxTtl: options.maxTtl ?? DEFAULT_LOCKS_CONFIG.maxTtl,\n keyPrefix: options.keyPrefix ?? DEFAULT_LOCKS_CONFIG.keyPrefix,\n retry: { ...DEFAULT_LOCKS_CONFIG.retry, ...options.retry },\n autoRenew: { ...DEFAULT_LOCKS_CONFIG.autoRenew, ...options.autoRenew },\n };\n }\n\n getImports(): Array<Type<unknown> | DynamicModule | ForwardReference> {\n return this.asyncOptions?.imports ?? [];\n }\n\n getProviders(): Provider[] {\n const optionsProvider: Provider = this.asyncOptions\n ? {\n provide: LOCKS_PLUGIN_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await this.asyncOptions!.useFactory(...args);\n return LocksPlugin.mergeDefaults(userOptions);\n },\n inject: this.asyncOptions.inject || [],\n }\n : {\n provide: LOCKS_PLUGIN_OPTIONS,\n useValue: LocksPlugin.mergeDefaults(this.options),\n };\n\n return [\n optionsProvider,\n\n // Store adapter\n {\n provide: LOCK_STORE,\n useClass: RedisLockStoreAdapter,\n },\n\n // Application service\n {\n provide: LOCK_SERVICE,\n useClass: LockService,\n },\n\n // @WithLock decorator initialization (proxy-based)\n LockDecoratorInitializerService,\n\n // Reflector is needed for decorator metadata\n Reflector,\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [LOCK_SERVICE];\n }\n}\n"]}
1
+ {"version":3,"sources":["../package.json","../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/lock/api/decorators/with-lock.decorator.ts","../src/lock/application/services/lock-decorator-initializer.service.ts","../src/lock/domain/entities/lock.entity.ts","../src/lock/application/services/lock.service.ts","../src/lock/infrastructure/scripts/lua-scripts.ts","../src/lock/infrastructure/adapters/redis-lock-store.adapter.ts","../src/locks.plugin.ts"],"names":["RedisXError","ErrorCode","Logger","Injectable","LockService","Inject","Optional","REDIS_DRIVER","Reflector"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"name\": \"@nestjs-redisx/locks\",\n \"version\": \"1.0.3\",\n \"description\": \"Distributed locks plugin for NestJS RedisX with auto-renewal and retry strategies\",\n \"author\": \"NestJS RedisX Team\",\n \"license\": \"MIT\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"SKIP_INTEGRATION=true vitest run\",\n \"test:watch\": \"SKIP_INTEGRATION=true vitest\",\n \"test:cov\": \"SKIP_INTEGRATION=true vitest run --coverage\",\n \"test:integration\": \"vitest run test/integration/locks.integration.spec.ts\",\n \"test:integration:watch\": \"vitest watch test/integration/locks.integration.spec.ts\",\n \"docker:up\": \"docker-compose up -d\",\n \"docker:down\": \"docker-compose down\",\n \"docker:logs\": \"docker-compose logs -f redis\",\n \"test:docker\": \"npm run docker:up && sleep 3 && npm run test:integration; TEST_EXIT=$?; npm run docker:down; exit $TEST_EXIT\",\n \"test:all\": \"npm test && npm run test:integration\",\n \"lint\": \"eslint \\\"{src,test}/**/*.ts\\\"\",\n \"format\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\"\n },\n \"keywords\": [\n \"nestjs\",\n \"redis\",\n \"locks\",\n \"distributed\",\n \"mutex\",\n \"semaphore\",\n \"auto-renewal\",\n \"retry\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/nestjs-redisx/nestjs-redisx.git\",\n \"directory\": \"packages/locks\"\n },\n \"homepage\": \"https://nestjs-redisx.dev/en/reference/locks/\",\n \"bugs\": {\n \"url\": \"https://github.com/nestjs-redisx/nestjs-redisx/issues\"\n },\n \"peerDependencies\": {\n \"@nestjs-redisx/core\": \"^1.0.0\",\n \"@nestjs/common\": \"^10.0.0 || ^11.0.0\",\n \"@nestjs/core\": \"^10.0.0 || ^11.0.0\",\n \"reflect-metadata\": \"^0.2.0\",\n \"rxjs\": \"^7.8.0\"\n },\n \"devDependencies\": {\n \"@nestjs/testing\": \"^10.0.0\",\n \"@types/node\": \"^20.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"^6.0.0\",\n \"@typescript-eslint/parser\": \"^6.0.0\",\n \"eslint\": \"^8.0.0\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.3.0\",\n \"vitest\": \"^1.6.0\",\n \"@vitest/coverage-v8\": \"^1.6.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","/**\n * Injection token for locks plugin options\n */\nexport const LOCKS_PLUGIN_OPTIONS = Symbol.for('LOCKS_PLUGIN_OPTIONS');\n\n/**\n * Injection token for lock service\n */\nexport const LOCK_SERVICE = Symbol.for('LOCK_SERVICE');\n\n/**\n * Injection token for lock store\n */\nexport const LOCK_STORE = Symbol.for('LOCK_STORE');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\n/**\n * Base error class for all lock-related errors.\n */\nexport class LockError extends RedisXError {\n constructor(\n message: string,\n code: ErrorCode,\n public readonly lockKey: string,\n cause?: Error,\n ) {\n super(message, code, cause, { lockKey });\n }\n}\n\n/**\n * Error thrown when lock acquisition fails.\n */\nexport class LockAcquisitionError extends LockError {\n constructor(\n key: string,\n public readonly reason: 'timeout' | 'held' | 'error',\n cause?: Error,\n ) {\n super(`Failed to acquire lock \"${key}\": ${reason}`, reason === 'timeout' ? ErrorCode.LOCK_ACQUISITION_TIMEOUT : ErrorCode.LOCK_ACQUISITION_FAILED, key, cause);\n }\n}\n\n/**\n * Error thrown when attempting to release or extend a lock not owned by the caller.\n */\nexport class LockNotOwnedError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n ) {\n super(`Lock \"${key}\" not owned by token \"${token}\"`, ErrorCode.LOCK_NOT_OWNED, key);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when lock extension fails.\n */\nexport class LockExtensionError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n cause?: Error,\n ) {\n super(`Failed to extend lock \"${key}\"`, ErrorCode.LOCK_EXTENSION_FAILED, key, cause);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when a lock has expired.\n */\nexport class LockExpiredError extends LockError {\n constructor(key: string) {\n super(`Lock \"${key}\" expired`, ErrorCode.LOCK_EXPIRED, key);\n }\n}\n","/**\n * @WithLock decorator for distributed locking.\n *\n * Uses immediate proxy-based wrapping (not deferred to interceptor).\n * Works on ANY Injectable class methods (services, repositories, etc).\n */\n\nimport { Logger } from '@nestjs/common';\nimport 'reflect-metadata';\nimport { LockAcquisitionError } from '../../../shared/errors';\n\nconst logger = new Logger('WithLock');\n\n/**\n * Metadata key for @WithLock decorator options.\n */\nexport const WITH_LOCK_OPTIONS = Symbol.for('WITH_LOCK_OPTIONS');\n\n/**\n * Lock interface for decorator use.\n */\ninterface IDecoratorLock {\n release(): Promise<void>;\n}\n\n/**\n * Lock service interface for decorator use.\n */\ninterface IDecoratorLockService {\n acquire(\n key: string,\n options?: {\n ttl?: number;\n waitTimeout?: number;\n autoRenew?: boolean;\n },\n ): Promise<IDecoratorLock>;\n}\n\n// Global service getter for lazy injection\nlet globalLockServiceGetter: (() => IDecoratorLockService) | null = null;\n\n/**\n * Register lock service getter for lazy injection.\n * Called by LocksPlugin during initialization.\n */\nexport function registerLockServiceGetter(getter: () => IDecoratorLockService): void {\n globalLockServiceGetter = getter;\n}\n\n/**\n * Options for @WithLock decorator.\n */\nexport interface IWithLockOptions {\n /**\n * Lock key or key builder function.\n *\n * @example\n * ```typescript\n * @WithLock({ key: 'update-user:{0}' }) // Uses first argument\n * @WithLock({ key: (dto) => `order:${dto.id}` }) // Custom function\n * ```\n */\n key: string | ((...args: unknown[]) => string);\n\n /**\n * Lock TTL in milliseconds.\n */\n ttl?: number;\n\n /**\n * Maximum time to wait for lock acquisition in milliseconds.\n */\n waitTimeout?: number;\n\n /**\n * Enable auto-renewal.\n */\n autoRenew?: boolean;\n\n /**\n * Action to take if lock acquisition fails.\n * - 'throw': Throw LockAcquisitionError (default)\n * - 'skip': Skip method execution and return undefined\n * - function: Throw custom error\n */\n onLockFailed?: 'throw' | 'skip' | ((key: string) => Error);\n}\n\n/**\n * Decorator for distributed locking.\n *\n * Acquires a distributed lock before executing the method\n * and automatically releases it afterwards.\n *\n * Works on any Injectable class method, not just controllers.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class OrderService {\n * @WithLock({ key: 'order:{0}' })\n * async processOrder(orderId: string) {\n * // Only one instance processes this order at a time\n * }\n *\n * @WithLock({\n * key: (dto) => `customer:${dto.customerId}`,\n * ttl: 60000,\n * autoRenew: true,\n * })\n * async createOrder(dto: CreateOrderDto) {\n * // Lock by customer ID with auto-renewal\n * }\n *\n * @WithLock({\n * key: 'sync:inventory',\n * onLockFailed: 'skip',\n * })\n * async syncInventory() {\n * // Will skip if already syncing\n * }\n * }\n * ```\n */\nexport function WithLock(options: IWithLockOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value as (...args: unknown[]) => Promise<unknown>;\n\n // Replace method with locking proxy\n descriptor.value = async function (...args: unknown[]): Promise<unknown> {\n // Lazy inject lock service on first call\n if (!globalLockServiceGetter) {\n logger.warn(`@WithLock: LockService not yet available, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n const lockService = globalLockServiceGetter();\n if (!lockService) {\n logger.warn(`@WithLock: LockService getter returned null, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n // Build lock key\n const key = buildLockKey(args, options);\n let lock: IDecoratorLock | null = null;\n\n try {\n // Acquire lock\n lock = await lockService.acquire(key, {\n ttl: options.ttl,\n waitTimeout: options.waitTimeout,\n autoRenew: options.autoRenew,\n });\n\n // Execute original method\n const result = await originalMethod.apply(this, args);\n\n return result;\n } catch (error) {\n // Handle lock acquisition failure\n if (error instanceof LockAcquisitionError) {\n return handleLockFailed(key, options, error);\n }\n throw error;\n } finally {\n // Always release lock\n if (lock) {\n await lock.release().catch((err: Error) => {\n logger.error(`@WithLock: Failed to release lock ${key}:`, err);\n });\n }\n }\n };\n\n // Preserve original method name\n Object.defineProperty(descriptor.value, 'name', {\n value: originalMethod.name,\n writable: false,\n });\n\n // Store metadata on WRAPPER function for reflection (after replacement)\n Reflect.defineMetadata(WITH_LOCK_OPTIONS, options, descriptor.value);\n\n return descriptor;\n };\n}\n\n/**\n * Builds lock key from template or function.\n */\nfunction buildLockKey(args: unknown[], options: IWithLockOptions): string {\n if (typeof options.key === 'function') {\n return options.key(...args);\n }\n return interpolateKey(options.key, args);\n}\n\n/**\n * Interpolates key template with arguments.\n *\n * Supports:\n * - {0}, {1}, etc. for positional arguments\n * - {0.id}, {1.name}, etc. for object properties\n */\nfunction interpolateKey(template: string, args: unknown[]): string {\n return template.replace(/\\{(\\d+)(?:\\.(\\w+))?\\}/g, (_, index, prop) => {\n const arg = args[Number(index)];\n if (prop && typeof arg === 'object' && arg !== null) {\n return String((arg as Record<string, unknown>)[prop]);\n }\n return String(arg);\n });\n}\n\n/**\n * Handles lock acquisition failure.\n */\nfunction handleLockFailed(key: string, options: IWithLockOptions, error: LockAcquisitionError): undefined {\n const handler = options.onLockFailed ?? 'throw';\n\n if (handler === 'throw') {\n throw error;\n }\n\n if (handler === 'skip') {\n return undefined;\n }\n\n if (typeof handler === 'function') {\n throw handler(key);\n }\n\n throw error;\n}\n","/**\n * Service for initializing @WithLock decorator with lazy lock service injection.\n *\n * Runs on module initialization and registers a getter function that provides\n * access to LockService for the @WithLock decorator's proxy logic.\n */\n\nimport { Injectable, OnModuleInit, Inject, Logger } from '@nestjs/common';\n\nimport { LOCK_SERVICE } from '../../../shared/constants';\nimport { registerLockServiceGetter } from '../../api/decorators/with-lock.decorator';\nimport { ILockService } from '../ports/lock-service.port';\n\n@Injectable()\nexport class LockDecoratorInitializerService implements OnModuleInit {\n private readonly logger = new Logger(LockDecoratorInitializerService.name);\n\n constructor(@Inject(LOCK_SERVICE) private readonly lockService: ILockService) {}\n\n /**\n * Called after all modules are initialized.\n * Registers lock service getter for @WithLock decorator.\n */\n // eslint-disable-next-line @typescript-eslint/require-await\n async onModuleInit(): Promise<void> {\n this.logger.debug('Registering LockService getter for @WithLock decorator');\n\n // Register getter that provides lock service to decorator\n registerLockServiceGetter(() => this.lockService);\n\n this.logger.log('@WithLock decorator initialized and ready to use');\n }\n}\n","import { LockNotOwnedError, LockExtensionError } from '../../../shared/errors';\nimport { ILockStore } from '../../application/ports/lock-store.port';\n\n/**\n * Represents an acquired distributed lock.\n */\nexport interface ILock {\n /** Lock key */\n readonly key: string;\n\n /** Unique token identifying lock ownership */\n readonly token: string;\n\n /** Lock TTL in milliseconds */\n readonly ttl: number;\n\n /** Timestamp when lock was acquired */\n readonly acquiredAt: Date;\n\n /** Timestamp when lock will expire */\n readonly expiresAt: Date;\n\n /** Whether auto-renewal is active */\n readonly isAutoRenewing: boolean;\n\n /**\n * Releases the lock.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n release(): Promise<void>;\n\n /**\n * Extends lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails\n */\n extend(ttl: number): Promise<void>;\n\n /**\n * Checks if lock is still held.\n *\n * @returns True if lock is held by this token\n */\n isHeld(): Promise<boolean>;\n\n /**\n * Stops automatic lock renewal.\n */\n stopAutoRenew(): void;\n}\n\n/**\n * Lock entity implementation.\n *\n * Represents a distributed lock with automatic renewal capability.\n * The lock maintains ownership through a unique token and can be\n * extended or released explicitly.\n *\n * @example\n * ```typescript\n * const lock = new Lock('my-resource', 'token-123', 30000, store);\n *\n * // Start auto-renewal every 15 seconds\n * lock.startAutoRenew(15000);\n *\n * try {\n * // Do work...\n * await performOperation();\n * } finally {\n * await lock.release();\n * }\n * ```\n */\nexport class Lock implements ILock {\n readonly key: string;\n readonly token: string;\n readonly ttl: number;\n readonly acquiredAt: Date;\n\n private _expiresAt: Date;\n private autoRenewTimer: NodeJS.Timeout | null = null;\n private released = false;\n\n /**\n * Creates a new Lock instance.\n *\n * @param key - Lock key in Redis\n * @param token - Unique ownership token\n * @param ttl - Time-to-live in milliseconds\n * @param store - Lock store for persistence operations\n */\n constructor(\n key: string,\n token: string,\n ttl: number,\n private readonly store: ILockStore,\n ) {\n this.key = key;\n this.token = token;\n this.ttl = ttl;\n this.acquiredAt = new Date();\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Gets the expiration timestamp.\n */\n get expiresAt(): Date {\n return this._expiresAt;\n }\n\n /**\n * Checks if auto-renewal is active.\n */\n get isAutoRenewing(): boolean {\n return this.autoRenewTimer !== null;\n }\n\n /**\n * Releases the lock.\n *\n * Stops auto-renewal and removes the lock from Redis.\n * Idempotent - can be called multiple times safely.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n async release(): Promise<void> {\n if (this.released) {\n return;\n }\n\n this.stopAutoRenew();\n\n const success = await this.store.release(this.key, this.token);\n if (!success) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n this.released = true;\n }\n\n /**\n * Extends the lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails (lock expired or not owned)\n */\n async extend(ttl: number): Promise<void> {\n if (this.released) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n const success = await this.store.extend(this.key, this.token, ttl);\n if (!success) {\n throw new LockExtensionError(this.key, this.token);\n }\n\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Checks if lock is still held.\n *\n * @returns False if released, otherwise checks Redis\n */\n async isHeld(): Promise<boolean> {\n if (this.released) {\n return false;\n }\n return this.store.isHeldBy(this.key, this.token);\n }\n\n /**\n * Starts automatic lock renewal.\n *\n * The lock will be extended at the specified interval\n * until stopAutoRenew() is called or extension fails.\n *\n * @param intervalMs - Renewal interval in milliseconds\n */\n startAutoRenew(intervalMs: number): void {\n if (this.autoRenewTimer) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.autoRenewTimer = setInterval(async () => {\n try {\n await this.extend(this.ttl);\n } catch {\n // Extension failed, stop renewing\n this.stopAutoRenew();\n }\n }, intervalMs);\n\n // Don't prevent Node.js process from exiting\n if (this.autoRenewTimer.unref) {\n this.autoRenewTimer.unref();\n }\n }\n\n /**\n * Stops automatic lock renewal.\n *\n * Safe to call multiple times.\n */\n stopAutoRenew(): void {\n if (this.autoRenewTimer) {\n clearInterval(this.autoRenewTimer);\n this.autoRenewTimer = null;\n }\n }\n}\n","import { Injectable, Inject, Logger, OnModuleDestroy, Optional } from '@nestjs/common';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_STORE } from '../../../shared/constants';\nimport { LockAcquisitionError } from '../../../shared/errors';\nimport { ILocksPluginOptions, ILockOptions } from '../../../shared/types';\nimport { Lock, ILock } from '../../domain/entities/lock.entity';\nimport { ILockService } from '../ports/lock-service.port';\nimport { ILockStore } from '../ports/lock-store.port';\n\n// Optional metrics integration\nconst METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\n\ninterface IMetricsService {\n incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void;\n setGauge(name: string, value: number, labels?: Record<string, string>): void;\n incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n}\n\n// Optional tracing integration\nconst TRACING_SERVICE = Symbol.for('TRACING_SERVICE');\n\ninterface ISpan {\n setAttribute(key: string, value: unknown): this;\n addEvent(name: string, attributes?: Record<string, unknown>): this;\n setStatus(status: 'OK' | 'ERROR'): this;\n recordException(error: Error): this;\n end(): void;\n}\n\ninterface ITracingService {\n startSpan(name: string, options?: { kind?: string; attributes?: Record<string, unknown> }): ISpan;\n}\n\n/**\n * Lock service implementation.\n *\n * Provides distributed locking with automatic retry, timeout, and renewal.\n * Implements graceful shutdown to release all active locks on module destroy.\n */\n@Injectable()\nexport class LockService implements ILockService, OnModuleDestroy {\n private readonly logger = new Logger(LockService.name);\n private readonly activeLocks = new Set<Lock>();\n\n constructor(\n @Inject(LOCKS_PLUGIN_OPTIONS) private readonly config: ILocksPluginOptions,\n @Inject(LOCK_STORE) private readonly store: ILockStore,\n @Optional() @Inject(METRICS_SERVICE) private readonly metrics?: IMetricsService,\n @Optional() @Inject(TRACING_SERVICE) private readonly tracing?: ITracingService,\n ) {}\n\n /**\n * Lifecycle hook: releases all active locks on shutdown.\n */\n async onModuleDestroy(): Promise<void> {\n // Release all active locks on graceful shutdown\n const releasePromises = Array.from(this.activeLocks).map((lock) =>\n lock.release().catch((error) => {\n // Log but don't throw - we're shutting down\n this.logger.error(`Failed to release lock ${lock.key} during shutdown:`, error);\n }),\n );\n\n await Promise.all(releasePromises);\n this.activeLocks.clear();\n }\n\n /**\n * Acquires lock with exponential backoff retry.\n */\n async acquire(key: string, options: ILockOptions = {}): Promise<ILock> {\n const span = this.tracing?.startSpan('lock.acquire', {\n kind: 'INTERNAL',\n attributes: { 'lock.key': key, 'lock.ttl': options.ttl },\n });\n\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const retry = this.resolveRetryConfig(options);\n const startTime = Date.now();\n\n let delay = retry.initialDelay;\n\n try {\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (acquired) {\n const waitDuration = (Date.now() - startTime) / 1000;\n this.metrics?.observeHistogram('redisx_lock_wait_duration_seconds', waitDuration);\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n span?.setAttribute('lock.acquired', true);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('OK');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n // Last attempt failed\n if (attempt === retry.maxRetries) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n span?.setAttribute('lock.acquired', false);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('ERROR');\n throw new LockAcquisitionError(key, 'timeout');\n }\n\n // Wait before retry\n await this.sleep(delay);\n delay = Math.min(delay * retry.multiplier, retry.maxDelay);\n }\n\n // Should never reach here, but satisfy TypeScript\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n throw new LockAcquisitionError(key, 'timeout');\n } catch (error) {\n span?.recordException(error as Error);\n span?.setStatus('ERROR');\n throw error;\n } finally {\n span?.end();\n }\n }\n\n /**\n * Tries to acquire lock once without retry.\n */\n async tryAcquire(key: string, options: ILockOptions = {}): Promise<ILock | null> {\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (!acquired) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n return null;\n }\n\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n /**\n * Executes function with automatic lock management.\n */\n async withLock<T>(key: string, fn: () => Promise<T>, options: ILockOptions = {}): Promise<T> {\n const lock = await this.acquire(key, options);\n const holdStart = Date.now();\n\n try {\n return await fn();\n } finally {\n const holdDuration = (Date.now() - holdStart) / 1000;\n this.metrics?.observeHistogram('redisx_lock_hold_duration_seconds', holdDuration);\n this.metrics?.decrementGauge('redisx_locks_active');\n\n await lock\n .release()\n .catch((error) => {\n this.logger.error(`Lock release failed for ${key}:`, error);\n })\n .finally(() => {\n this.activeLocks.delete(lock as Lock);\n });\n }\n }\n\n /**\n * Checks if key is locked.\n */\n async isLocked(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.exists(fullKey);\n }\n\n /**\n * Force releases lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.forceRelease(fullKey);\n }\n\n /**\n * Creates lock instance with optional auto-renewal.\n */\n private createLock(fullKey: string, token: string, ttl: number, options: ILockOptions): Lock {\n const lock = new Lock(fullKey, token, ttl, this.store);\n\n // Setup auto-renew if enabled\n const autoRenewEnabled = options.autoRenew ?? this.config.autoRenew?.enabled ?? true;\n if (autoRenewEnabled) {\n const intervalFraction = this.config.autoRenew?.intervalFraction ?? 0.5;\n const interval = ttl * intervalFraction;\n lock.startAutoRenew(interval);\n }\n\n return lock;\n }\n\n /**\n * Builds full lock key with prefix.\n */\n private buildKey(key: string): string {\n const prefix = this.config.keyPrefix ?? '_lock:';\n return `${prefix}${key}`;\n }\n\n /**\n * Generates unique lock token.\n */\n private generateToken(): string {\n return `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n }\n\n /**\n * Resolves TTL with defaults and limits.\n */\n private resolveTtl(ttl?: number): number {\n const resolvedTtl = ttl ?? this.config.defaultTtl ?? 30000;\n const maxTtl = this.config.maxTtl ?? 300000;\n return Math.min(resolvedTtl, maxTtl);\n }\n\n /**\n * Resolves retry configuration.\n */\n private resolveRetryConfig(options: ILockOptions) {\n return {\n maxRetries: options.retry?.maxRetries ?? this.config.retry?.maxRetries ?? 3,\n initialDelay: options.retry?.initialDelay ?? this.config.retry?.initialDelay ?? 100,\n maxDelay: this.config.retry?.maxDelay ?? 3000,\n multiplier: this.config.retry?.multiplier ?? 2,\n };\n }\n\n /**\n * Sleeps for specified milliseconds.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Inline Lua scripts for lock operations.\n *\n * Scripts are stored as inline strings to avoid issues with file reading\n * after build (dist directory doesn't contain .lua files).\n */\n\n/**\n * Release lock if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * Returns: 1 if released, 0 if not owned or doesn't exist\n */\nexport const RELEASE_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\nelse\n return 0\nend\n`.trim();\n\n/**\n * Extend lock TTL if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * ARGV[2] = TTL in milliseconds\n * Returns: 1 if extended, 0 if not owned or doesn't exist\n */\nexport const EXTEND_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"pexpire\", KEYS[1], ARGV[2])\nelse\n return 0\nend\n`.trim();\n","import { Injectable, Inject, OnModuleInit } from '@nestjs/common';\nimport { IRedisDriver, REDIS_DRIVER } from '@nestjs-redisx/core';\n\nimport { ILockStore } from '../../application/ports/lock-store.port';\nimport { RELEASE_LOCK_SCRIPT, EXTEND_LOCK_SCRIPT } from '../scripts/lua-scripts';\n\n/**\n * Redis-based lock store implementation.\n *\n * Uses atomic Redis operations for lock management:\n * - SET NX PX for acquiring locks\n * - Lua scripts for safe release and extension\n */\n@Injectable()\nexport class RedisLockStoreAdapter implements ILockStore, OnModuleInit {\n private releaseSha: string | null = null;\n private extendSha: string | null = null;\n\n constructor(@Inject(REDIS_DRIVER) private readonly driver: IRedisDriver) {}\n\n /**\n * Lifecycle hook: loads Lua scripts into Redis on initialization.\n */\n async onModuleInit(): Promise<void> {\n // Pre-load Lua scripts and cache their SHA hashes\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n /**\n * Acquires lock using SET NX PX.\n */\n async acquire(key: string, token: string, ttlMs: number): Promise<boolean> {\n const result = await this.driver.set(key, token, {\n nx: true, // Only set if key doesn't exist\n px: ttlMs, // TTL in milliseconds\n });\n return result === 'OK';\n }\n\n /**\n * Releases lock if owned by token (Lua script).\n */\n async release(key: string, token: string): Promise<boolean> {\n if (!this.releaseSha) {\n // Fallback if script not loaded\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.releaseSha, [key], [token]);\n return result === 1;\n }\n\n /**\n * Extends lock TTL if owned by token (Lua script).\n */\n async extend(key: string, token: string, ttlMs: number): Promise<boolean> {\n if (!this.extendSha) {\n // Fallback if script not loaded\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.extendSha, [key], [token, ttlMs]);\n return result === 1;\n }\n\n /**\n * Checks if lock key exists.\n */\n async exists(key: string): Promise<boolean> {\n const count = await this.driver.exists(key);\n return count > 0;\n }\n\n /**\n * Checks if lock is held by specific token.\n */\n async isHeldBy(key: string, token: string): Promise<boolean> {\n const value = await this.driver.get(key);\n return value === token;\n }\n\n /**\n * Force removes lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const count = await this.driver.del(key);\n return count > 0;\n }\n}\n","/**\n * Locks plugin for NestJS RedisX.\n * Provides distributed locking with auto-renewal and retry strategies.\n */\n\nimport { DynamicModule, ForwardReference, Provider, Type } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IRedisXPlugin, IPluginAsyncOptions } from '@nestjs-redisx/core';\n\nimport { version } from '../package.json';\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_SERVICE, LOCK_STORE } from './shared/constants';\nimport { ILocksPluginOptions } from './shared/types';\nimport { LockDecoratorInitializerService } from './lock/application/services/lock-decorator-initializer.service';\nimport { LockService } from './lock/application/services/lock.service';\nimport { RedisLockStoreAdapter } from './lock/infrastructure/adapters/redis-lock-store.adapter';\n\nconst DEFAULT_LOCKS_CONFIG: Required<Omit<ILocksPluginOptions, 'isGlobal'>> = {\n defaultTtl: 30000,\n maxTtl: 300000,\n keyPrefix: '_lock:',\n retry: {\n maxRetries: 3,\n initialDelay: 100,\n maxDelay: 3000,\n multiplier: 2,\n },\n autoRenew: {\n enabled: true,\n intervalFraction: 0.5,\n },\n};\n\n/**\n * Distributed locks plugin for NestJS RedisX.\n *\n * Provides distributed locking with auto-renewal and retry strategies.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new LocksPlugin({\n * defaultTtl: 30000,\n * keyPrefix: '_lock:',\n * autoRenew: { enabled: true },\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class LocksPlugin implements IRedisXPlugin {\n readonly name = 'locks';\n readonly version: string = version;\n readonly description = 'Distributed locking with auto-renewal and retry strategies';\n\n private asyncOptions?: IPluginAsyncOptions<ILocksPluginOptions>;\n\n constructor(private readonly options: ILocksPluginOptions = {}) {}\n\n static registerAsync(asyncOptions: IPluginAsyncOptions<ILocksPluginOptions>): LocksPlugin {\n const plugin = new LocksPlugin();\n plugin.asyncOptions = asyncOptions;\n return plugin;\n }\n\n private static mergeDefaults(options: ILocksPluginOptions): ILocksPluginOptions {\n return {\n defaultTtl: options.defaultTtl ?? DEFAULT_LOCKS_CONFIG.defaultTtl,\n maxTtl: options.maxTtl ?? DEFAULT_LOCKS_CONFIG.maxTtl,\n keyPrefix: options.keyPrefix ?? DEFAULT_LOCKS_CONFIG.keyPrefix,\n retry: { ...DEFAULT_LOCKS_CONFIG.retry, ...options.retry },\n autoRenew: { ...DEFAULT_LOCKS_CONFIG.autoRenew, ...options.autoRenew },\n };\n }\n\n getImports(): Array<Type<unknown> | DynamicModule | ForwardReference> {\n return this.asyncOptions?.imports ?? [];\n }\n\n getProviders(): Provider[] {\n const optionsProvider: Provider = this.asyncOptions\n ? {\n provide: LOCKS_PLUGIN_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await this.asyncOptions!.useFactory(...args);\n return LocksPlugin.mergeDefaults(userOptions);\n },\n inject: this.asyncOptions.inject || [],\n }\n : {\n provide: LOCKS_PLUGIN_OPTIONS,\n useValue: LocksPlugin.mergeDefaults(this.options),\n };\n\n return [\n optionsProvider,\n\n // Store adapter\n {\n provide: LOCK_STORE,\n useClass: RedisLockStoreAdapter,\n },\n\n // Application service\n {\n provide: LOCK_SERVICE,\n useClass: LockService,\n },\n\n // @WithLock decorator initialization (proxy-based)\n LockDecoratorInitializerService,\n\n // Reflector is needed for decorator metadata\n Reflector,\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [LOCK_SERVICE];\n }\n}\n"]}
package/dist/index.mjs CHANGED
@@ -13,6 +13,9 @@ var __decorateClass = (decorators, target, key, kind) => {
13
13
  };
14
14
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
15
15
 
16
+ // package.json
17
+ var version = "1.0.3";
18
+
16
19
  // src/shared/constants/index.ts
17
20
  var LOCKS_PLUGIN_OPTIONS = /* @__PURE__ */ Symbol.for("LOCKS_PLUGIN_OPTIONS");
18
21
  var LOCK_SERVICE = /* @__PURE__ */ Symbol.for("LOCK_SERVICE");
@@ -577,7 +580,7 @@ var LocksPlugin = class _LocksPlugin {
577
580
  this.options = options;
578
581
  }
579
582
  name = "locks";
580
- version = "0.1.0";
583
+ version = version;
581
584
  description = "Distributed locking with auto-renewal and retry strategies";
582
585
  asyncOptions;
583
586
  static registerAsync(asyncOptions) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/lock/api/decorators/with-lock.decorator.ts","../src/lock/application/services/lock-decorator-initializer.service.ts","../src/lock/domain/entities/lock.entity.ts","../src/lock/application/services/lock.service.ts","../src/lock/infrastructure/scripts/lua-scripts.ts","../src/lock/infrastructure/adapters/redis-lock-store.adapter.ts","../src/locks.plugin.ts"],"names":["Logger","Injectable","Inject"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Injection token for locks plugin options\n */\nexport const LOCKS_PLUGIN_OPTIONS = Symbol.for('LOCKS_PLUGIN_OPTIONS');\n\n/**\n * Injection token for lock service\n */\nexport const LOCK_SERVICE = Symbol.for('LOCK_SERVICE');\n\n/**\n * Injection token for lock store\n */\nexport const LOCK_STORE = Symbol.for('LOCK_STORE');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\n/**\n * Base error class for all lock-related errors.\n */\nexport class LockError extends RedisXError {\n constructor(\n message: string,\n code: ErrorCode,\n public readonly lockKey: string,\n cause?: Error,\n ) {\n super(message, code, cause, { lockKey });\n }\n}\n\n/**\n * Error thrown when lock acquisition fails.\n */\nexport class LockAcquisitionError extends LockError {\n constructor(\n key: string,\n public readonly reason: 'timeout' | 'held' | 'error',\n cause?: Error,\n ) {\n super(`Failed to acquire lock \"${key}\": ${reason}`, reason === 'timeout' ? ErrorCode.LOCK_ACQUISITION_TIMEOUT : ErrorCode.LOCK_ACQUISITION_FAILED, key, cause);\n }\n}\n\n/**\n * Error thrown when attempting to release or extend a lock not owned by the caller.\n */\nexport class LockNotOwnedError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n ) {\n super(`Lock \"${key}\" not owned by token \"${token}\"`, ErrorCode.LOCK_NOT_OWNED, key);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when lock extension fails.\n */\nexport class LockExtensionError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n cause?: Error,\n ) {\n super(`Failed to extend lock \"${key}\"`, ErrorCode.LOCK_EXTENSION_FAILED, key, cause);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when a lock has expired.\n */\nexport class LockExpiredError extends LockError {\n constructor(key: string) {\n super(`Lock \"${key}\" expired`, ErrorCode.LOCK_EXPIRED, key);\n }\n}\n","/**\n * @WithLock decorator for distributed locking.\n *\n * Uses immediate proxy-based wrapping (not deferred to interceptor).\n * Works on ANY Injectable class methods (services, repositories, etc).\n */\n\nimport { Logger } from '@nestjs/common';\nimport 'reflect-metadata';\nimport { LockAcquisitionError } from '../../../shared/errors';\n\nconst logger = new Logger('WithLock');\n\n/**\n * Metadata key for @WithLock decorator options.\n */\nexport const WITH_LOCK_OPTIONS = Symbol.for('WITH_LOCK_OPTIONS');\n\n/**\n * Lock interface for decorator use.\n */\ninterface IDecoratorLock {\n release(): Promise<void>;\n}\n\n/**\n * Lock service interface for decorator use.\n */\ninterface IDecoratorLockService {\n acquire(\n key: string,\n options?: {\n ttl?: number;\n waitTimeout?: number;\n autoRenew?: boolean;\n },\n ): Promise<IDecoratorLock>;\n}\n\n// Global service getter for lazy injection\nlet globalLockServiceGetter: (() => IDecoratorLockService) | null = null;\n\n/**\n * Register lock service getter for lazy injection.\n * Called by LocksPlugin during initialization.\n */\nexport function registerLockServiceGetter(getter: () => IDecoratorLockService): void {\n globalLockServiceGetter = getter;\n}\n\n/**\n * Options for @WithLock decorator.\n */\nexport interface IWithLockOptions {\n /**\n * Lock key or key builder function.\n *\n * @example\n * ```typescript\n * @WithLock({ key: 'update-user:{0}' }) // Uses first argument\n * @WithLock({ key: (dto) => `order:${dto.id}` }) // Custom function\n * ```\n */\n key: string | ((...args: unknown[]) => string);\n\n /**\n * Lock TTL in milliseconds.\n */\n ttl?: number;\n\n /**\n * Maximum time to wait for lock acquisition in milliseconds.\n */\n waitTimeout?: number;\n\n /**\n * Enable auto-renewal.\n */\n autoRenew?: boolean;\n\n /**\n * Action to take if lock acquisition fails.\n * - 'throw': Throw LockAcquisitionError (default)\n * - 'skip': Skip method execution and return undefined\n * - function: Throw custom error\n */\n onLockFailed?: 'throw' | 'skip' | ((key: string) => Error);\n}\n\n/**\n * Decorator for distributed locking.\n *\n * Acquires a distributed lock before executing the method\n * and automatically releases it afterwards.\n *\n * Works on any Injectable class method, not just controllers.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class OrderService {\n * @WithLock({ key: 'order:{0}' })\n * async processOrder(orderId: string) {\n * // Only one instance processes this order at a time\n * }\n *\n * @WithLock({\n * key: (dto) => `customer:${dto.customerId}`,\n * ttl: 60000,\n * autoRenew: true,\n * })\n * async createOrder(dto: CreateOrderDto) {\n * // Lock by customer ID with auto-renewal\n * }\n *\n * @WithLock({\n * key: 'sync:inventory',\n * onLockFailed: 'skip',\n * })\n * async syncInventory() {\n * // Will skip if already syncing\n * }\n * }\n * ```\n */\nexport function WithLock(options: IWithLockOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value as (...args: unknown[]) => Promise<unknown>;\n\n // Replace method with locking proxy\n descriptor.value = async function (...args: unknown[]): Promise<unknown> {\n // Lazy inject lock service on first call\n if (!globalLockServiceGetter) {\n logger.warn(`@WithLock: LockService not yet available, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n const lockService = globalLockServiceGetter();\n if (!lockService) {\n logger.warn(`@WithLock: LockService getter returned null, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n // Build lock key\n const key = buildLockKey(args, options);\n let lock: IDecoratorLock | null = null;\n\n try {\n // Acquire lock\n lock = await lockService.acquire(key, {\n ttl: options.ttl,\n waitTimeout: options.waitTimeout,\n autoRenew: options.autoRenew,\n });\n\n // Execute original method\n const result = await originalMethod.apply(this, args);\n\n return result;\n } catch (error) {\n // Handle lock acquisition failure\n if (error instanceof LockAcquisitionError) {\n return handleLockFailed(key, options, error);\n }\n throw error;\n } finally {\n // Always release lock\n if (lock) {\n await lock.release().catch((err: Error) => {\n logger.error(`@WithLock: Failed to release lock ${key}:`, err);\n });\n }\n }\n };\n\n // Preserve original method name\n Object.defineProperty(descriptor.value, 'name', {\n value: originalMethod.name,\n writable: false,\n });\n\n // Store metadata on WRAPPER function for reflection (after replacement)\n Reflect.defineMetadata(WITH_LOCK_OPTIONS, options, descriptor.value);\n\n return descriptor;\n };\n}\n\n/**\n * Builds lock key from template or function.\n */\nfunction buildLockKey(args: unknown[], options: IWithLockOptions): string {\n if (typeof options.key === 'function') {\n return options.key(...args);\n }\n return interpolateKey(options.key, args);\n}\n\n/**\n * Interpolates key template with arguments.\n *\n * Supports:\n * - {0}, {1}, etc. for positional arguments\n * - {0.id}, {1.name}, etc. for object properties\n */\nfunction interpolateKey(template: string, args: unknown[]): string {\n return template.replace(/\\{(\\d+)(?:\\.(\\w+))?\\}/g, (_, index, prop) => {\n const arg = args[Number(index)];\n if (prop && typeof arg === 'object' && arg !== null) {\n return String((arg as Record<string, unknown>)[prop]);\n }\n return String(arg);\n });\n}\n\n/**\n * Handles lock acquisition failure.\n */\nfunction handleLockFailed(key: string, options: IWithLockOptions, error: LockAcquisitionError): undefined {\n const handler = options.onLockFailed ?? 'throw';\n\n if (handler === 'throw') {\n throw error;\n }\n\n if (handler === 'skip') {\n return undefined;\n }\n\n if (typeof handler === 'function') {\n throw handler(key);\n }\n\n throw error;\n}\n","/**\n * Service for initializing @WithLock decorator with lazy lock service injection.\n *\n * Runs on module initialization and registers a getter function that provides\n * access to LockService for the @WithLock decorator's proxy logic.\n */\n\nimport { Injectable, OnModuleInit, Inject, Logger } from '@nestjs/common';\n\nimport { LOCK_SERVICE } from '../../../shared/constants';\nimport { registerLockServiceGetter } from '../../api/decorators/with-lock.decorator';\nimport { ILockService } from '../ports/lock-service.port';\n\n@Injectable()\nexport class LockDecoratorInitializerService implements OnModuleInit {\n private readonly logger = new Logger(LockDecoratorInitializerService.name);\n\n constructor(@Inject(LOCK_SERVICE) private readonly lockService: ILockService) {}\n\n /**\n * Called after all modules are initialized.\n * Registers lock service getter for @WithLock decorator.\n */\n // eslint-disable-next-line @typescript-eslint/require-await\n async onModuleInit(): Promise<void> {\n this.logger.debug('Registering LockService getter for @WithLock decorator');\n\n // Register getter that provides lock service to decorator\n registerLockServiceGetter(() => this.lockService);\n\n this.logger.log('@WithLock decorator initialized and ready to use');\n }\n}\n","import { LockNotOwnedError, LockExtensionError } from '../../../shared/errors';\nimport { ILockStore } from '../../application/ports/lock-store.port';\n\n/**\n * Represents an acquired distributed lock.\n */\nexport interface ILock {\n /** Lock key */\n readonly key: string;\n\n /** Unique token identifying lock ownership */\n readonly token: string;\n\n /** Lock TTL in milliseconds */\n readonly ttl: number;\n\n /** Timestamp when lock was acquired */\n readonly acquiredAt: Date;\n\n /** Timestamp when lock will expire */\n readonly expiresAt: Date;\n\n /** Whether auto-renewal is active */\n readonly isAutoRenewing: boolean;\n\n /**\n * Releases the lock.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n release(): Promise<void>;\n\n /**\n * Extends lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails\n */\n extend(ttl: number): Promise<void>;\n\n /**\n * Checks if lock is still held.\n *\n * @returns True if lock is held by this token\n */\n isHeld(): Promise<boolean>;\n\n /**\n * Stops automatic lock renewal.\n */\n stopAutoRenew(): void;\n}\n\n/**\n * Lock entity implementation.\n *\n * Represents a distributed lock with automatic renewal capability.\n * The lock maintains ownership through a unique token and can be\n * extended or released explicitly.\n *\n * @example\n * ```typescript\n * const lock = new Lock('my-resource', 'token-123', 30000, store);\n *\n * // Start auto-renewal every 15 seconds\n * lock.startAutoRenew(15000);\n *\n * try {\n * // Do work...\n * await performOperation();\n * } finally {\n * await lock.release();\n * }\n * ```\n */\nexport class Lock implements ILock {\n readonly key: string;\n readonly token: string;\n readonly ttl: number;\n readonly acquiredAt: Date;\n\n private _expiresAt: Date;\n private autoRenewTimer: NodeJS.Timeout | null = null;\n private released = false;\n\n /**\n * Creates a new Lock instance.\n *\n * @param key - Lock key in Redis\n * @param token - Unique ownership token\n * @param ttl - Time-to-live in milliseconds\n * @param store - Lock store for persistence operations\n */\n constructor(\n key: string,\n token: string,\n ttl: number,\n private readonly store: ILockStore,\n ) {\n this.key = key;\n this.token = token;\n this.ttl = ttl;\n this.acquiredAt = new Date();\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Gets the expiration timestamp.\n */\n get expiresAt(): Date {\n return this._expiresAt;\n }\n\n /**\n * Checks if auto-renewal is active.\n */\n get isAutoRenewing(): boolean {\n return this.autoRenewTimer !== null;\n }\n\n /**\n * Releases the lock.\n *\n * Stops auto-renewal and removes the lock from Redis.\n * Idempotent - can be called multiple times safely.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n async release(): Promise<void> {\n if (this.released) {\n return;\n }\n\n this.stopAutoRenew();\n\n const success = await this.store.release(this.key, this.token);\n if (!success) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n this.released = true;\n }\n\n /**\n * Extends the lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails (lock expired or not owned)\n */\n async extend(ttl: number): Promise<void> {\n if (this.released) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n const success = await this.store.extend(this.key, this.token, ttl);\n if (!success) {\n throw new LockExtensionError(this.key, this.token);\n }\n\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Checks if lock is still held.\n *\n * @returns False if released, otherwise checks Redis\n */\n async isHeld(): Promise<boolean> {\n if (this.released) {\n return false;\n }\n return this.store.isHeldBy(this.key, this.token);\n }\n\n /**\n * Starts automatic lock renewal.\n *\n * The lock will be extended at the specified interval\n * until stopAutoRenew() is called or extension fails.\n *\n * @param intervalMs - Renewal interval in milliseconds\n */\n startAutoRenew(intervalMs: number): void {\n if (this.autoRenewTimer) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.autoRenewTimer = setInterval(async () => {\n try {\n await this.extend(this.ttl);\n } catch {\n // Extension failed, stop renewing\n this.stopAutoRenew();\n }\n }, intervalMs);\n\n // Don't prevent Node.js process from exiting\n if (this.autoRenewTimer.unref) {\n this.autoRenewTimer.unref();\n }\n }\n\n /**\n * Stops automatic lock renewal.\n *\n * Safe to call multiple times.\n */\n stopAutoRenew(): void {\n if (this.autoRenewTimer) {\n clearInterval(this.autoRenewTimer);\n this.autoRenewTimer = null;\n }\n }\n}\n","import { Injectable, Inject, Logger, OnModuleDestroy, Optional } from '@nestjs/common';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_STORE } from '../../../shared/constants';\nimport { LockAcquisitionError } from '../../../shared/errors';\nimport { ILocksPluginOptions, ILockOptions } from '../../../shared/types';\nimport { Lock, ILock } from '../../domain/entities/lock.entity';\nimport { ILockService } from '../ports/lock-service.port';\nimport { ILockStore } from '../ports/lock-store.port';\n\n// Optional metrics integration\nconst METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\n\ninterface IMetricsService {\n incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void;\n setGauge(name: string, value: number, labels?: Record<string, string>): void;\n incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n}\n\n// Optional tracing integration\nconst TRACING_SERVICE = Symbol.for('TRACING_SERVICE');\n\ninterface ISpan {\n setAttribute(key: string, value: unknown): this;\n addEvent(name: string, attributes?: Record<string, unknown>): this;\n setStatus(status: 'OK' | 'ERROR'): this;\n recordException(error: Error): this;\n end(): void;\n}\n\ninterface ITracingService {\n startSpan(name: string, options?: { kind?: string; attributes?: Record<string, unknown> }): ISpan;\n}\n\n/**\n * Lock service implementation.\n *\n * Provides distributed locking with automatic retry, timeout, and renewal.\n * Implements graceful shutdown to release all active locks on module destroy.\n */\n@Injectable()\nexport class LockService implements ILockService, OnModuleDestroy {\n private readonly logger = new Logger(LockService.name);\n private readonly activeLocks = new Set<Lock>();\n\n constructor(\n @Inject(LOCKS_PLUGIN_OPTIONS) private readonly config: ILocksPluginOptions,\n @Inject(LOCK_STORE) private readonly store: ILockStore,\n @Optional() @Inject(METRICS_SERVICE) private readonly metrics?: IMetricsService,\n @Optional() @Inject(TRACING_SERVICE) private readonly tracing?: ITracingService,\n ) {}\n\n /**\n * Lifecycle hook: releases all active locks on shutdown.\n */\n async onModuleDestroy(): Promise<void> {\n // Release all active locks on graceful shutdown\n const releasePromises = Array.from(this.activeLocks).map((lock) =>\n lock.release().catch((error) => {\n // Log but don't throw - we're shutting down\n this.logger.error(`Failed to release lock ${lock.key} during shutdown:`, error);\n }),\n );\n\n await Promise.all(releasePromises);\n this.activeLocks.clear();\n }\n\n /**\n * Acquires lock with exponential backoff retry.\n */\n async acquire(key: string, options: ILockOptions = {}): Promise<ILock> {\n const span = this.tracing?.startSpan('lock.acquire', {\n kind: 'INTERNAL',\n attributes: { 'lock.key': key, 'lock.ttl': options.ttl },\n });\n\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const retry = this.resolveRetryConfig(options);\n const startTime = Date.now();\n\n let delay = retry.initialDelay;\n\n try {\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (acquired) {\n const waitDuration = (Date.now() - startTime) / 1000;\n this.metrics?.observeHistogram('redisx_lock_wait_duration_seconds', waitDuration);\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n span?.setAttribute('lock.acquired', true);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('OK');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n // Last attempt failed\n if (attempt === retry.maxRetries) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n span?.setAttribute('lock.acquired', false);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('ERROR');\n throw new LockAcquisitionError(key, 'timeout');\n }\n\n // Wait before retry\n await this.sleep(delay);\n delay = Math.min(delay * retry.multiplier, retry.maxDelay);\n }\n\n // Should never reach here, but satisfy TypeScript\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n throw new LockAcquisitionError(key, 'timeout');\n } catch (error) {\n span?.recordException(error as Error);\n span?.setStatus('ERROR');\n throw error;\n } finally {\n span?.end();\n }\n }\n\n /**\n * Tries to acquire lock once without retry.\n */\n async tryAcquire(key: string, options: ILockOptions = {}): Promise<ILock | null> {\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (!acquired) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n return null;\n }\n\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n /**\n * Executes function with automatic lock management.\n */\n async withLock<T>(key: string, fn: () => Promise<T>, options: ILockOptions = {}): Promise<T> {\n const lock = await this.acquire(key, options);\n const holdStart = Date.now();\n\n try {\n return await fn();\n } finally {\n const holdDuration = (Date.now() - holdStart) / 1000;\n this.metrics?.observeHistogram('redisx_lock_hold_duration_seconds', holdDuration);\n this.metrics?.decrementGauge('redisx_locks_active');\n\n await lock\n .release()\n .catch((error) => {\n this.logger.error(`Lock release failed for ${key}:`, error);\n })\n .finally(() => {\n this.activeLocks.delete(lock as Lock);\n });\n }\n }\n\n /**\n * Checks if key is locked.\n */\n async isLocked(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.exists(fullKey);\n }\n\n /**\n * Force releases lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.forceRelease(fullKey);\n }\n\n /**\n * Creates lock instance with optional auto-renewal.\n */\n private createLock(fullKey: string, token: string, ttl: number, options: ILockOptions): Lock {\n const lock = new Lock(fullKey, token, ttl, this.store);\n\n // Setup auto-renew if enabled\n const autoRenewEnabled = options.autoRenew ?? this.config.autoRenew?.enabled ?? true;\n if (autoRenewEnabled) {\n const intervalFraction = this.config.autoRenew?.intervalFraction ?? 0.5;\n const interval = ttl * intervalFraction;\n lock.startAutoRenew(interval);\n }\n\n return lock;\n }\n\n /**\n * Builds full lock key with prefix.\n */\n private buildKey(key: string): string {\n const prefix = this.config.keyPrefix ?? '_lock:';\n return `${prefix}${key}`;\n }\n\n /**\n * Generates unique lock token.\n */\n private generateToken(): string {\n return `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n }\n\n /**\n * Resolves TTL with defaults and limits.\n */\n private resolveTtl(ttl?: number): number {\n const resolvedTtl = ttl ?? this.config.defaultTtl ?? 30000;\n const maxTtl = this.config.maxTtl ?? 300000;\n return Math.min(resolvedTtl, maxTtl);\n }\n\n /**\n * Resolves retry configuration.\n */\n private resolveRetryConfig(options: ILockOptions) {\n return {\n maxRetries: options.retry?.maxRetries ?? this.config.retry?.maxRetries ?? 3,\n initialDelay: options.retry?.initialDelay ?? this.config.retry?.initialDelay ?? 100,\n maxDelay: this.config.retry?.maxDelay ?? 3000,\n multiplier: this.config.retry?.multiplier ?? 2,\n };\n }\n\n /**\n * Sleeps for specified milliseconds.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Inline Lua scripts for lock operations.\n *\n * Scripts are stored as inline strings to avoid issues with file reading\n * after build (dist directory doesn't contain .lua files).\n */\n\n/**\n * Release lock if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * Returns: 1 if released, 0 if not owned or doesn't exist\n */\nexport const RELEASE_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\nelse\n return 0\nend\n`.trim();\n\n/**\n * Extend lock TTL if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * ARGV[2] = TTL in milliseconds\n * Returns: 1 if extended, 0 if not owned or doesn't exist\n */\nexport const EXTEND_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"pexpire\", KEYS[1], ARGV[2])\nelse\n return 0\nend\n`.trim();\n","import { Injectable, Inject, OnModuleInit } from '@nestjs/common';\nimport { IRedisDriver, REDIS_DRIVER } from '@nestjs-redisx/core';\n\nimport { ILockStore } from '../../application/ports/lock-store.port';\nimport { RELEASE_LOCK_SCRIPT, EXTEND_LOCK_SCRIPT } from '../scripts/lua-scripts';\n\n/**\n * Redis-based lock store implementation.\n *\n * Uses atomic Redis operations for lock management:\n * - SET NX PX for acquiring locks\n * - Lua scripts for safe release and extension\n */\n@Injectable()\nexport class RedisLockStoreAdapter implements ILockStore, OnModuleInit {\n private releaseSha: string | null = null;\n private extendSha: string | null = null;\n\n constructor(@Inject(REDIS_DRIVER) private readonly driver: IRedisDriver) {}\n\n /**\n * Lifecycle hook: loads Lua scripts into Redis on initialization.\n */\n async onModuleInit(): Promise<void> {\n // Pre-load Lua scripts and cache their SHA hashes\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n /**\n * Acquires lock using SET NX PX.\n */\n async acquire(key: string, token: string, ttlMs: number): Promise<boolean> {\n const result = await this.driver.set(key, token, {\n nx: true, // Only set if key doesn't exist\n px: ttlMs, // TTL in milliseconds\n });\n return result === 'OK';\n }\n\n /**\n * Releases lock if owned by token (Lua script).\n */\n async release(key: string, token: string): Promise<boolean> {\n if (!this.releaseSha) {\n // Fallback if script not loaded\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.releaseSha, [key], [token]);\n return result === 1;\n }\n\n /**\n * Extends lock TTL if owned by token (Lua script).\n */\n async extend(key: string, token: string, ttlMs: number): Promise<boolean> {\n if (!this.extendSha) {\n // Fallback if script not loaded\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.extendSha, [key], [token, ttlMs]);\n return result === 1;\n }\n\n /**\n * Checks if lock key exists.\n */\n async exists(key: string): Promise<boolean> {\n const count = await this.driver.exists(key);\n return count > 0;\n }\n\n /**\n * Checks if lock is held by specific token.\n */\n async isHeldBy(key: string, token: string): Promise<boolean> {\n const value = await this.driver.get(key);\n return value === token;\n }\n\n /**\n * Force removes lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const count = await this.driver.del(key);\n return count > 0;\n }\n}\n","/**\n * Locks plugin for NestJS RedisX.\n * Provides distributed locking with auto-renewal and retry strategies.\n */\n\nimport { DynamicModule, ForwardReference, Provider, Type } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IRedisXPlugin, IPluginAsyncOptions } from '@nestjs-redisx/core';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_SERVICE, LOCK_STORE } from './shared/constants';\nimport { ILocksPluginOptions } from './shared/types';\nimport { LockDecoratorInitializerService } from './lock/application/services/lock-decorator-initializer.service';\nimport { LockService } from './lock/application/services/lock.service';\nimport { RedisLockStoreAdapter } from './lock/infrastructure/adapters/redis-lock-store.adapter';\n\nconst DEFAULT_LOCKS_CONFIG: Required<Omit<ILocksPluginOptions, 'isGlobal'>> = {\n defaultTtl: 30000,\n maxTtl: 300000,\n keyPrefix: '_lock:',\n retry: {\n maxRetries: 3,\n initialDelay: 100,\n maxDelay: 3000,\n multiplier: 2,\n },\n autoRenew: {\n enabled: true,\n intervalFraction: 0.5,\n },\n};\n\n/**\n * Distributed locks plugin for NestJS RedisX.\n *\n * Provides distributed locking with auto-renewal and retry strategies.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new LocksPlugin({\n * defaultTtl: 30000,\n * keyPrefix: '_lock:',\n * autoRenew: { enabled: true },\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class LocksPlugin implements IRedisXPlugin {\n readonly name = 'locks';\n readonly version = '0.1.0';\n readonly description = 'Distributed locking with auto-renewal and retry strategies';\n\n private asyncOptions?: IPluginAsyncOptions<ILocksPluginOptions>;\n\n constructor(private readonly options: ILocksPluginOptions = {}) {}\n\n static registerAsync(asyncOptions: IPluginAsyncOptions<ILocksPluginOptions>): LocksPlugin {\n const plugin = new LocksPlugin();\n plugin.asyncOptions = asyncOptions;\n return plugin;\n }\n\n private static mergeDefaults(options: ILocksPluginOptions): ILocksPluginOptions {\n return {\n defaultTtl: options.defaultTtl ?? DEFAULT_LOCKS_CONFIG.defaultTtl,\n maxTtl: options.maxTtl ?? DEFAULT_LOCKS_CONFIG.maxTtl,\n keyPrefix: options.keyPrefix ?? DEFAULT_LOCKS_CONFIG.keyPrefix,\n retry: { ...DEFAULT_LOCKS_CONFIG.retry, ...options.retry },\n autoRenew: { ...DEFAULT_LOCKS_CONFIG.autoRenew, ...options.autoRenew },\n };\n }\n\n getImports(): Array<Type<unknown> | DynamicModule | ForwardReference> {\n return this.asyncOptions?.imports ?? [];\n }\n\n getProviders(): Provider[] {\n const optionsProvider: Provider = this.asyncOptions\n ? {\n provide: LOCKS_PLUGIN_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await this.asyncOptions!.useFactory(...args);\n return LocksPlugin.mergeDefaults(userOptions);\n },\n inject: this.asyncOptions.inject || [],\n }\n : {\n provide: LOCKS_PLUGIN_OPTIONS,\n useValue: LocksPlugin.mergeDefaults(this.options),\n };\n\n return [\n optionsProvider,\n\n // Store adapter\n {\n provide: LOCK_STORE,\n useClass: RedisLockStoreAdapter,\n },\n\n // Application service\n {\n provide: LOCK_SERVICE,\n useClass: LockService,\n },\n\n // @WithLock decorator initialization (proxy-based)\n LockDecoratorInitializerService,\n\n // Reflector is needed for decorator metadata\n Reflector,\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [LOCK_SERVICE];\n }\n}\n"]}
1
+ {"version":3,"sources":["../package.json","../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/lock/api/decorators/with-lock.decorator.ts","../src/lock/application/services/lock-decorator-initializer.service.ts","../src/lock/domain/entities/lock.entity.ts","../src/lock/application/services/lock.service.ts","../src/lock/infrastructure/scripts/lua-scripts.ts","../src/lock/infrastructure/adapters/redis-lock-store.adapter.ts","../src/locks.plugin.ts"],"names":["Logger","Injectable","Inject"],"mappings":"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","file":"index.mjs","sourcesContent":["{\n \"name\": \"@nestjs-redisx/locks\",\n \"version\": \"1.0.3\",\n \"description\": \"Distributed locks plugin for NestJS RedisX with auto-renewal and retry strategies\",\n \"author\": \"NestJS RedisX Team\",\n \"license\": \"MIT\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"SKIP_INTEGRATION=true vitest run\",\n \"test:watch\": \"SKIP_INTEGRATION=true vitest\",\n \"test:cov\": \"SKIP_INTEGRATION=true vitest run --coverage\",\n \"test:integration\": \"vitest run test/integration/locks.integration.spec.ts\",\n \"test:integration:watch\": \"vitest watch test/integration/locks.integration.spec.ts\",\n \"docker:up\": \"docker-compose up -d\",\n \"docker:down\": \"docker-compose down\",\n \"docker:logs\": \"docker-compose logs -f redis\",\n \"test:docker\": \"npm run docker:up && sleep 3 && npm run test:integration; TEST_EXIT=$?; npm run docker:down; exit $TEST_EXIT\",\n \"test:all\": \"npm test && npm run test:integration\",\n \"lint\": \"eslint \\\"{src,test}/**/*.ts\\\"\",\n \"format\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\"\n },\n \"keywords\": [\n \"nestjs\",\n \"redis\",\n \"locks\",\n \"distributed\",\n \"mutex\",\n \"semaphore\",\n \"auto-renewal\",\n \"retry\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/nestjs-redisx/nestjs-redisx.git\",\n \"directory\": \"packages/locks\"\n },\n \"homepage\": \"https://nestjs-redisx.dev/en/reference/locks/\",\n \"bugs\": {\n \"url\": \"https://github.com/nestjs-redisx/nestjs-redisx/issues\"\n },\n \"peerDependencies\": {\n \"@nestjs-redisx/core\": \"^1.0.0\",\n \"@nestjs/common\": \"^10.0.0 || ^11.0.0\",\n \"@nestjs/core\": \"^10.0.0 || ^11.0.0\",\n \"reflect-metadata\": \"^0.2.0\",\n \"rxjs\": \"^7.8.0\"\n },\n \"devDependencies\": {\n \"@nestjs/testing\": \"^10.0.0\",\n \"@types/node\": \"^20.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"^6.0.0\",\n \"@typescript-eslint/parser\": \"^6.0.0\",\n \"eslint\": \"^8.0.0\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.3.0\",\n \"vitest\": \"^1.6.0\",\n \"@vitest/coverage-v8\": \"^1.6.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","/**\n * Injection token for locks plugin options\n */\nexport const LOCKS_PLUGIN_OPTIONS = Symbol.for('LOCKS_PLUGIN_OPTIONS');\n\n/**\n * Injection token for lock service\n */\nexport const LOCK_SERVICE = Symbol.for('LOCK_SERVICE');\n\n/**\n * Injection token for lock store\n */\nexport const LOCK_STORE = Symbol.for('LOCK_STORE');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\n/**\n * Base error class for all lock-related errors.\n */\nexport class LockError extends RedisXError {\n constructor(\n message: string,\n code: ErrorCode,\n public readonly lockKey: string,\n cause?: Error,\n ) {\n super(message, code, cause, { lockKey });\n }\n}\n\n/**\n * Error thrown when lock acquisition fails.\n */\nexport class LockAcquisitionError extends LockError {\n constructor(\n key: string,\n public readonly reason: 'timeout' | 'held' | 'error',\n cause?: Error,\n ) {\n super(`Failed to acquire lock \"${key}\": ${reason}`, reason === 'timeout' ? ErrorCode.LOCK_ACQUISITION_TIMEOUT : ErrorCode.LOCK_ACQUISITION_FAILED, key, cause);\n }\n}\n\n/**\n * Error thrown when attempting to release or extend a lock not owned by the caller.\n */\nexport class LockNotOwnedError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n ) {\n super(`Lock \"${key}\" not owned by token \"${token}\"`, ErrorCode.LOCK_NOT_OWNED, key);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when lock extension fails.\n */\nexport class LockExtensionError extends LockError {\n constructor(\n key: string,\n public readonly token: string,\n cause?: Error,\n ) {\n super(`Failed to extend lock \"${key}\"`, ErrorCode.LOCK_EXTENSION_FAILED, key, cause);\n }\n\n override toJSON() {\n return {\n ...super.toJSON(),\n token: this.token,\n };\n }\n}\n\n/**\n * Error thrown when a lock has expired.\n */\nexport class LockExpiredError extends LockError {\n constructor(key: string) {\n super(`Lock \"${key}\" expired`, ErrorCode.LOCK_EXPIRED, key);\n }\n}\n","/**\n * @WithLock decorator for distributed locking.\n *\n * Uses immediate proxy-based wrapping (not deferred to interceptor).\n * Works on ANY Injectable class methods (services, repositories, etc).\n */\n\nimport { Logger } from '@nestjs/common';\nimport 'reflect-metadata';\nimport { LockAcquisitionError } from '../../../shared/errors';\n\nconst logger = new Logger('WithLock');\n\n/**\n * Metadata key for @WithLock decorator options.\n */\nexport const WITH_LOCK_OPTIONS = Symbol.for('WITH_LOCK_OPTIONS');\n\n/**\n * Lock interface for decorator use.\n */\ninterface IDecoratorLock {\n release(): Promise<void>;\n}\n\n/**\n * Lock service interface for decorator use.\n */\ninterface IDecoratorLockService {\n acquire(\n key: string,\n options?: {\n ttl?: number;\n waitTimeout?: number;\n autoRenew?: boolean;\n },\n ): Promise<IDecoratorLock>;\n}\n\n// Global service getter for lazy injection\nlet globalLockServiceGetter: (() => IDecoratorLockService) | null = null;\n\n/**\n * Register lock service getter for lazy injection.\n * Called by LocksPlugin during initialization.\n */\nexport function registerLockServiceGetter(getter: () => IDecoratorLockService): void {\n globalLockServiceGetter = getter;\n}\n\n/**\n * Options for @WithLock decorator.\n */\nexport interface IWithLockOptions {\n /**\n * Lock key or key builder function.\n *\n * @example\n * ```typescript\n * @WithLock({ key: 'update-user:{0}' }) // Uses first argument\n * @WithLock({ key: (dto) => `order:${dto.id}` }) // Custom function\n * ```\n */\n key: string | ((...args: unknown[]) => string);\n\n /**\n * Lock TTL in milliseconds.\n */\n ttl?: number;\n\n /**\n * Maximum time to wait for lock acquisition in milliseconds.\n */\n waitTimeout?: number;\n\n /**\n * Enable auto-renewal.\n */\n autoRenew?: boolean;\n\n /**\n * Action to take if lock acquisition fails.\n * - 'throw': Throw LockAcquisitionError (default)\n * - 'skip': Skip method execution and return undefined\n * - function: Throw custom error\n */\n onLockFailed?: 'throw' | 'skip' | ((key: string) => Error);\n}\n\n/**\n * Decorator for distributed locking.\n *\n * Acquires a distributed lock before executing the method\n * and automatically releases it afterwards.\n *\n * Works on any Injectable class method, not just controllers.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class OrderService {\n * @WithLock({ key: 'order:{0}' })\n * async processOrder(orderId: string) {\n * // Only one instance processes this order at a time\n * }\n *\n * @WithLock({\n * key: (dto) => `customer:${dto.customerId}`,\n * ttl: 60000,\n * autoRenew: true,\n * })\n * async createOrder(dto: CreateOrderDto) {\n * // Lock by customer ID with auto-renewal\n * }\n *\n * @WithLock({\n * key: 'sync:inventory',\n * onLockFailed: 'skip',\n * })\n * async syncInventory() {\n * // Will skip if already syncing\n * }\n * }\n * ```\n */\nexport function WithLock(options: IWithLockOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value as (...args: unknown[]) => Promise<unknown>;\n\n // Replace method with locking proxy\n descriptor.value = async function (...args: unknown[]): Promise<unknown> {\n // Lazy inject lock service on first call\n if (!globalLockServiceGetter) {\n logger.warn(`@WithLock: LockService not yet available, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n const lockService = globalLockServiceGetter();\n if (!lockService) {\n logger.warn(`@WithLock: LockService getter returned null, executing method without lock`);\n return originalMethod.apply(this, args);\n }\n\n // Build lock key\n const key = buildLockKey(args, options);\n let lock: IDecoratorLock | null = null;\n\n try {\n // Acquire lock\n lock = await lockService.acquire(key, {\n ttl: options.ttl,\n waitTimeout: options.waitTimeout,\n autoRenew: options.autoRenew,\n });\n\n // Execute original method\n const result = await originalMethod.apply(this, args);\n\n return result;\n } catch (error) {\n // Handle lock acquisition failure\n if (error instanceof LockAcquisitionError) {\n return handleLockFailed(key, options, error);\n }\n throw error;\n } finally {\n // Always release lock\n if (lock) {\n await lock.release().catch((err: Error) => {\n logger.error(`@WithLock: Failed to release lock ${key}:`, err);\n });\n }\n }\n };\n\n // Preserve original method name\n Object.defineProperty(descriptor.value, 'name', {\n value: originalMethod.name,\n writable: false,\n });\n\n // Store metadata on WRAPPER function for reflection (after replacement)\n Reflect.defineMetadata(WITH_LOCK_OPTIONS, options, descriptor.value);\n\n return descriptor;\n };\n}\n\n/**\n * Builds lock key from template or function.\n */\nfunction buildLockKey(args: unknown[], options: IWithLockOptions): string {\n if (typeof options.key === 'function') {\n return options.key(...args);\n }\n return interpolateKey(options.key, args);\n}\n\n/**\n * Interpolates key template with arguments.\n *\n * Supports:\n * - {0}, {1}, etc. for positional arguments\n * - {0.id}, {1.name}, etc. for object properties\n */\nfunction interpolateKey(template: string, args: unknown[]): string {\n return template.replace(/\\{(\\d+)(?:\\.(\\w+))?\\}/g, (_, index, prop) => {\n const arg = args[Number(index)];\n if (prop && typeof arg === 'object' && arg !== null) {\n return String((arg as Record<string, unknown>)[prop]);\n }\n return String(arg);\n });\n}\n\n/**\n * Handles lock acquisition failure.\n */\nfunction handleLockFailed(key: string, options: IWithLockOptions, error: LockAcquisitionError): undefined {\n const handler = options.onLockFailed ?? 'throw';\n\n if (handler === 'throw') {\n throw error;\n }\n\n if (handler === 'skip') {\n return undefined;\n }\n\n if (typeof handler === 'function') {\n throw handler(key);\n }\n\n throw error;\n}\n","/**\n * Service for initializing @WithLock decorator with lazy lock service injection.\n *\n * Runs on module initialization and registers a getter function that provides\n * access to LockService for the @WithLock decorator's proxy logic.\n */\n\nimport { Injectable, OnModuleInit, Inject, Logger } from '@nestjs/common';\n\nimport { LOCK_SERVICE } from '../../../shared/constants';\nimport { registerLockServiceGetter } from '../../api/decorators/with-lock.decorator';\nimport { ILockService } from '../ports/lock-service.port';\n\n@Injectable()\nexport class LockDecoratorInitializerService implements OnModuleInit {\n private readonly logger = new Logger(LockDecoratorInitializerService.name);\n\n constructor(@Inject(LOCK_SERVICE) private readonly lockService: ILockService) {}\n\n /**\n * Called after all modules are initialized.\n * Registers lock service getter for @WithLock decorator.\n */\n // eslint-disable-next-line @typescript-eslint/require-await\n async onModuleInit(): Promise<void> {\n this.logger.debug('Registering LockService getter for @WithLock decorator');\n\n // Register getter that provides lock service to decorator\n registerLockServiceGetter(() => this.lockService);\n\n this.logger.log('@WithLock decorator initialized and ready to use');\n }\n}\n","import { LockNotOwnedError, LockExtensionError } from '../../../shared/errors';\nimport { ILockStore } from '../../application/ports/lock-store.port';\n\n/**\n * Represents an acquired distributed lock.\n */\nexport interface ILock {\n /** Lock key */\n readonly key: string;\n\n /** Unique token identifying lock ownership */\n readonly token: string;\n\n /** Lock TTL in milliseconds */\n readonly ttl: number;\n\n /** Timestamp when lock was acquired */\n readonly acquiredAt: Date;\n\n /** Timestamp when lock will expire */\n readonly expiresAt: Date;\n\n /** Whether auto-renewal is active */\n readonly isAutoRenewing: boolean;\n\n /**\n * Releases the lock.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n release(): Promise<void>;\n\n /**\n * Extends lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails\n */\n extend(ttl: number): Promise<void>;\n\n /**\n * Checks if lock is still held.\n *\n * @returns True if lock is held by this token\n */\n isHeld(): Promise<boolean>;\n\n /**\n * Stops automatic lock renewal.\n */\n stopAutoRenew(): void;\n}\n\n/**\n * Lock entity implementation.\n *\n * Represents a distributed lock with automatic renewal capability.\n * The lock maintains ownership through a unique token and can be\n * extended or released explicitly.\n *\n * @example\n * ```typescript\n * const lock = new Lock('my-resource', 'token-123', 30000, store);\n *\n * // Start auto-renewal every 15 seconds\n * lock.startAutoRenew(15000);\n *\n * try {\n * // Do work...\n * await performOperation();\n * } finally {\n * await lock.release();\n * }\n * ```\n */\nexport class Lock implements ILock {\n readonly key: string;\n readonly token: string;\n readonly ttl: number;\n readonly acquiredAt: Date;\n\n private _expiresAt: Date;\n private autoRenewTimer: NodeJS.Timeout | null = null;\n private released = false;\n\n /**\n * Creates a new Lock instance.\n *\n * @param key - Lock key in Redis\n * @param token - Unique ownership token\n * @param ttl - Time-to-live in milliseconds\n * @param store - Lock store for persistence operations\n */\n constructor(\n key: string,\n token: string,\n ttl: number,\n private readonly store: ILockStore,\n ) {\n this.key = key;\n this.token = token;\n this.ttl = ttl;\n this.acquiredAt = new Date();\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Gets the expiration timestamp.\n */\n get expiresAt(): Date {\n return this._expiresAt;\n }\n\n /**\n * Checks if auto-renewal is active.\n */\n get isAutoRenewing(): boolean {\n return this.autoRenewTimer !== null;\n }\n\n /**\n * Releases the lock.\n *\n * Stops auto-renewal and removes the lock from Redis.\n * Idempotent - can be called multiple times safely.\n *\n * @throws {LockNotOwnedError} If lock is not owned by this token\n */\n async release(): Promise<void> {\n if (this.released) {\n return;\n }\n\n this.stopAutoRenew();\n\n const success = await this.store.release(this.key, this.token);\n if (!success) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n this.released = true;\n }\n\n /**\n * Extends the lock TTL.\n *\n * @param ttl - New TTL in milliseconds\n * @throws {LockNotOwnedError} If lock was already released\n * @throws {LockExtensionError} If extension fails (lock expired or not owned)\n */\n async extend(ttl: number): Promise<void> {\n if (this.released) {\n throw new LockNotOwnedError(this.key, this.token);\n }\n\n const success = await this.store.extend(this.key, this.token, ttl);\n if (!success) {\n throw new LockExtensionError(this.key, this.token);\n }\n\n this._expiresAt = new Date(Date.now() + ttl);\n }\n\n /**\n * Checks if lock is still held.\n *\n * @returns False if released, otherwise checks Redis\n */\n async isHeld(): Promise<boolean> {\n if (this.released) {\n return false;\n }\n return this.store.isHeldBy(this.key, this.token);\n }\n\n /**\n * Starts automatic lock renewal.\n *\n * The lock will be extended at the specified interval\n * until stopAutoRenew() is called or extension fails.\n *\n * @param intervalMs - Renewal interval in milliseconds\n */\n startAutoRenew(intervalMs: number): void {\n if (this.autoRenewTimer) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.autoRenewTimer = setInterval(async () => {\n try {\n await this.extend(this.ttl);\n } catch {\n // Extension failed, stop renewing\n this.stopAutoRenew();\n }\n }, intervalMs);\n\n // Don't prevent Node.js process from exiting\n if (this.autoRenewTimer.unref) {\n this.autoRenewTimer.unref();\n }\n }\n\n /**\n * Stops automatic lock renewal.\n *\n * Safe to call multiple times.\n */\n stopAutoRenew(): void {\n if (this.autoRenewTimer) {\n clearInterval(this.autoRenewTimer);\n this.autoRenewTimer = null;\n }\n }\n}\n","import { Injectable, Inject, Logger, OnModuleDestroy, Optional } from '@nestjs/common';\n\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_STORE } from '../../../shared/constants';\nimport { LockAcquisitionError } from '../../../shared/errors';\nimport { ILocksPluginOptions, ILockOptions } from '../../../shared/types';\nimport { Lock, ILock } from '../../domain/entities/lock.entity';\nimport { ILockService } from '../ports/lock-service.port';\nimport { ILockStore } from '../ports/lock-store.port';\n\n// Optional metrics integration\nconst METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\n\ninterface IMetricsService {\n incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void;\n setGauge(name: string, value: number, labels?: Record<string, string>): void;\n incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;\n}\n\n// Optional tracing integration\nconst TRACING_SERVICE = Symbol.for('TRACING_SERVICE');\n\ninterface ISpan {\n setAttribute(key: string, value: unknown): this;\n addEvent(name: string, attributes?: Record<string, unknown>): this;\n setStatus(status: 'OK' | 'ERROR'): this;\n recordException(error: Error): this;\n end(): void;\n}\n\ninterface ITracingService {\n startSpan(name: string, options?: { kind?: string; attributes?: Record<string, unknown> }): ISpan;\n}\n\n/**\n * Lock service implementation.\n *\n * Provides distributed locking with automatic retry, timeout, and renewal.\n * Implements graceful shutdown to release all active locks on module destroy.\n */\n@Injectable()\nexport class LockService implements ILockService, OnModuleDestroy {\n private readonly logger = new Logger(LockService.name);\n private readonly activeLocks = new Set<Lock>();\n\n constructor(\n @Inject(LOCKS_PLUGIN_OPTIONS) private readonly config: ILocksPluginOptions,\n @Inject(LOCK_STORE) private readonly store: ILockStore,\n @Optional() @Inject(METRICS_SERVICE) private readonly metrics?: IMetricsService,\n @Optional() @Inject(TRACING_SERVICE) private readonly tracing?: ITracingService,\n ) {}\n\n /**\n * Lifecycle hook: releases all active locks on shutdown.\n */\n async onModuleDestroy(): Promise<void> {\n // Release all active locks on graceful shutdown\n const releasePromises = Array.from(this.activeLocks).map((lock) =>\n lock.release().catch((error) => {\n // Log but don't throw - we're shutting down\n this.logger.error(`Failed to release lock ${lock.key} during shutdown:`, error);\n }),\n );\n\n await Promise.all(releasePromises);\n this.activeLocks.clear();\n }\n\n /**\n * Acquires lock with exponential backoff retry.\n */\n async acquire(key: string, options: ILockOptions = {}): Promise<ILock> {\n const span = this.tracing?.startSpan('lock.acquire', {\n kind: 'INTERNAL',\n attributes: { 'lock.key': key, 'lock.ttl': options.ttl },\n });\n\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const retry = this.resolveRetryConfig(options);\n const startTime = Date.now();\n\n let delay = retry.initialDelay;\n\n try {\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (acquired) {\n const waitDuration = (Date.now() - startTime) / 1000;\n this.metrics?.observeHistogram('redisx_lock_wait_duration_seconds', waitDuration);\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n span?.setAttribute('lock.acquired', true);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('OK');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n // Last attempt failed\n if (attempt === retry.maxRetries) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n span?.setAttribute('lock.acquired', false);\n span?.setAttribute('lock.attempts', attempt + 1);\n span?.setStatus('ERROR');\n throw new LockAcquisitionError(key, 'timeout');\n }\n\n // Wait before retry\n await this.sleep(delay);\n delay = Math.min(delay * retry.multiplier, retry.maxDelay);\n }\n\n // Should never reach here, but satisfy TypeScript\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n throw new LockAcquisitionError(key, 'timeout');\n } catch (error) {\n span?.recordException(error as Error);\n span?.setStatus('ERROR');\n throw error;\n } finally {\n span?.end();\n }\n }\n\n /**\n * Tries to acquire lock once without retry.\n */\n async tryAcquire(key: string, options: ILockOptions = {}): Promise<ILock | null> {\n const fullKey = this.buildKey(key);\n const ttl = this.resolveTtl(options.ttl);\n const token = this.generateToken();\n\n const acquired = await this.store.acquire(fullKey, token, ttl);\n\n if (!acquired) {\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'failed' });\n return null;\n }\n\n this.metrics?.incrementCounter('redisx_lock_acquisitions_total', { status: 'acquired' });\n this.metrics?.incrementGauge('redisx_locks_active');\n\n const lock = this.createLock(fullKey, token, ttl, options);\n this.activeLocks.add(lock);\n return lock;\n }\n\n /**\n * Executes function with automatic lock management.\n */\n async withLock<T>(key: string, fn: () => Promise<T>, options: ILockOptions = {}): Promise<T> {\n const lock = await this.acquire(key, options);\n const holdStart = Date.now();\n\n try {\n return await fn();\n } finally {\n const holdDuration = (Date.now() - holdStart) / 1000;\n this.metrics?.observeHistogram('redisx_lock_hold_duration_seconds', holdDuration);\n this.metrics?.decrementGauge('redisx_locks_active');\n\n await lock\n .release()\n .catch((error) => {\n this.logger.error(`Lock release failed for ${key}:`, error);\n })\n .finally(() => {\n this.activeLocks.delete(lock as Lock);\n });\n }\n }\n\n /**\n * Checks if key is locked.\n */\n async isLocked(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.exists(fullKey);\n }\n\n /**\n * Force releases lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const fullKey = this.buildKey(key);\n return this.store.forceRelease(fullKey);\n }\n\n /**\n * Creates lock instance with optional auto-renewal.\n */\n private createLock(fullKey: string, token: string, ttl: number, options: ILockOptions): Lock {\n const lock = new Lock(fullKey, token, ttl, this.store);\n\n // Setup auto-renew if enabled\n const autoRenewEnabled = options.autoRenew ?? this.config.autoRenew?.enabled ?? true;\n if (autoRenewEnabled) {\n const intervalFraction = this.config.autoRenew?.intervalFraction ?? 0.5;\n const interval = ttl * intervalFraction;\n lock.startAutoRenew(interval);\n }\n\n return lock;\n }\n\n /**\n * Builds full lock key with prefix.\n */\n private buildKey(key: string): string {\n const prefix = this.config.keyPrefix ?? '_lock:';\n return `${prefix}${key}`;\n }\n\n /**\n * Generates unique lock token.\n */\n private generateToken(): string {\n return `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n }\n\n /**\n * Resolves TTL with defaults and limits.\n */\n private resolveTtl(ttl?: number): number {\n const resolvedTtl = ttl ?? this.config.defaultTtl ?? 30000;\n const maxTtl = this.config.maxTtl ?? 300000;\n return Math.min(resolvedTtl, maxTtl);\n }\n\n /**\n * Resolves retry configuration.\n */\n private resolveRetryConfig(options: ILockOptions) {\n return {\n maxRetries: options.retry?.maxRetries ?? this.config.retry?.maxRetries ?? 3,\n initialDelay: options.retry?.initialDelay ?? this.config.retry?.initialDelay ?? 100,\n maxDelay: this.config.retry?.maxDelay ?? 3000,\n multiplier: this.config.retry?.multiplier ?? 2,\n };\n }\n\n /**\n * Sleeps for specified milliseconds.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Inline Lua scripts for lock operations.\n *\n * Scripts are stored as inline strings to avoid issues with file reading\n * after build (dist directory doesn't contain .lua files).\n */\n\n/**\n * Release lock if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * Returns: 1 if released, 0 if not owned or doesn't exist\n */\nexport const RELEASE_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\nelse\n return 0\nend\n`.trim();\n\n/**\n * Extend lock TTL if owned by token.\n *\n * KEYS[1] = lock key\n * ARGV[1] = owner token\n * ARGV[2] = TTL in milliseconds\n * Returns: 1 if extended, 0 if not owned or doesn't exist\n */\nexport const EXTEND_LOCK_SCRIPT = `\nif redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"pexpire\", KEYS[1], ARGV[2])\nelse\n return 0\nend\n`.trim();\n","import { Injectable, Inject, OnModuleInit } from '@nestjs/common';\nimport { IRedisDriver, REDIS_DRIVER } from '@nestjs-redisx/core';\n\nimport { ILockStore } from '../../application/ports/lock-store.port';\nimport { RELEASE_LOCK_SCRIPT, EXTEND_LOCK_SCRIPT } from '../scripts/lua-scripts';\n\n/**\n * Redis-based lock store implementation.\n *\n * Uses atomic Redis operations for lock management:\n * - SET NX PX for acquiring locks\n * - Lua scripts for safe release and extension\n */\n@Injectable()\nexport class RedisLockStoreAdapter implements ILockStore, OnModuleInit {\n private releaseSha: string | null = null;\n private extendSha: string | null = null;\n\n constructor(@Inject(REDIS_DRIVER) private readonly driver: IRedisDriver) {}\n\n /**\n * Lifecycle hook: loads Lua scripts into Redis on initialization.\n */\n async onModuleInit(): Promise<void> {\n // Pre-load Lua scripts and cache their SHA hashes\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n /**\n * Acquires lock using SET NX PX.\n */\n async acquire(key: string, token: string, ttlMs: number): Promise<boolean> {\n const result = await this.driver.set(key, token, {\n nx: true, // Only set if key doesn't exist\n px: ttlMs, // TTL in milliseconds\n });\n return result === 'OK';\n }\n\n /**\n * Releases lock if owned by token (Lua script).\n */\n async release(key: string, token: string): Promise<boolean> {\n if (!this.releaseSha) {\n // Fallback if script not loaded\n this.releaseSha = await this.driver.scriptLoad(RELEASE_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.releaseSha, [key], [token]);\n return result === 1;\n }\n\n /**\n * Extends lock TTL if owned by token (Lua script).\n */\n async extend(key: string, token: string, ttlMs: number): Promise<boolean> {\n if (!this.extendSha) {\n // Fallback if script not loaded\n this.extendSha = await this.driver.scriptLoad(EXTEND_LOCK_SCRIPT);\n }\n\n const result = await this.driver.evalsha(this.extendSha, [key], [token, ttlMs]);\n return result === 1;\n }\n\n /**\n * Checks if lock key exists.\n */\n async exists(key: string): Promise<boolean> {\n const count = await this.driver.exists(key);\n return count > 0;\n }\n\n /**\n * Checks if lock is held by specific token.\n */\n async isHeldBy(key: string, token: string): Promise<boolean> {\n const value = await this.driver.get(key);\n return value === token;\n }\n\n /**\n * Force removes lock without ownership check.\n */\n async forceRelease(key: string): Promise<boolean> {\n const count = await this.driver.del(key);\n return count > 0;\n }\n}\n","/**\n * Locks plugin for NestJS RedisX.\n * Provides distributed locking with auto-renewal and retry strategies.\n */\n\nimport { DynamicModule, ForwardReference, Provider, Type } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IRedisXPlugin, IPluginAsyncOptions } from '@nestjs-redisx/core';\n\nimport { version } from '../package.json';\nimport { LOCKS_PLUGIN_OPTIONS, LOCK_SERVICE, LOCK_STORE } from './shared/constants';\nimport { ILocksPluginOptions } from './shared/types';\nimport { LockDecoratorInitializerService } from './lock/application/services/lock-decorator-initializer.service';\nimport { LockService } from './lock/application/services/lock.service';\nimport { RedisLockStoreAdapter } from './lock/infrastructure/adapters/redis-lock-store.adapter';\n\nconst DEFAULT_LOCKS_CONFIG: Required<Omit<ILocksPluginOptions, 'isGlobal'>> = {\n defaultTtl: 30000,\n maxTtl: 300000,\n keyPrefix: '_lock:',\n retry: {\n maxRetries: 3,\n initialDelay: 100,\n maxDelay: 3000,\n multiplier: 2,\n },\n autoRenew: {\n enabled: true,\n intervalFraction: 0.5,\n },\n};\n\n/**\n * Distributed locks plugin for NestJS RedisX.\n *\n * Provides distributed locking with auto-renewal and retry strategies.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new LocksPlugin({\n * defaultTtl: 30000,\n * keyPrefix: '_lock:',\n * autoRenew: { enabled: true },\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class LocksPlugin implements IRedisXPlugin {\n readonly name = 'locks';\n readonly version: string = version;\n readonly description = 'Distributed locking with auto-renewal and retry strategies';\n\n private asyncOptions?: IPluginAsyncOptions<ILocksPluginOptions>;\n\n constructor(private readonly options: ILocksPluginOptions = {}) {}\n\n static registerAsync(asyncOptions: IPluginAsyncOptions<ILocksPluginOptions>): LocksPlugin {\n const plugin = new LocksPlugin();\n plugin.asyncOptions = asyncOptions;\n return plugin;\n }\n\n private static mergeDefaults(options: ILocksPluginOptions): ILocksPluginOptions {\n return {\n defaultTtl: options.defaultTtl ?? DEFAULT_LOCKS_CONFIG.defaultTtl,\n maxTtl: options.maxTtl ?? DEFAULT_LOCKS_CONFIG.maxTtl,\n keyPrefix: options.keyPrefix ?? DEFAULT_LOCKS_CONFIG.keyPrefix,\n retry: { ...DEFAULT_LOCKS_CONFIG.retry, ...options.retry },\n autoRenew: { ...DEFAULT_LOCKS_CONFIG.autoRenew, ...options.autoRenew },\n };\n }\n\n getImports(): Array<Type<unknown> | DynamicModule | ForwardReference> {\n return this.asyncOptions?.imports ?? [];\n }\n\n getProviders(): Provider[] {\n const optionsProvider: Provider = this.asyncOptions\n ? {\n provide: LOCKS_PLUGIN_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await this.asyncOptions!.useFactory(...args);\n return LocksPlugin.mergeDefaults(userOptions);\n },\n inject: this.asyncOptions.inject || [],\n }\n : {\n provide: LOCKS_PLUGIN_OPTIONS,\n useValue: LocksPlugin.mergeDefaults(this.options),\n };\n\n return [\n optionsProvider,\n\n // Store adapter\n {\n provide: LOCK_STORE,\n useClass: RedisLockStoreAdapter,\n },\n\n // Application service\n {\n provide: LOCK_SERVICE,\n useClass: LockService,\n },\n\n // @WithLock decorator initialization (proxy-based)\n LockDecoratorInitializerService,\n\n // Reflector is needed for decorator metadata\n Reflector,\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [LOCK_SERVICE];\n }\n}\n"]}
@@ -32,7 +32,7 @@ import { ILocksPluginOptions } from './shared/types';
32
32
  export declare class LocksPlugin implements IRedisXPlugin {
33
33
  private readonly options;
34
34
  readonly name = "locks";
35
- readonly version = "0.1.0";
35
+ readonly version: string;
36
36
  readonly description = "Distributed locking with auto-renewal and retry strategies";
37
37
  private asyncOptions?;
38
38
  constructor(options?: ILocksPluginOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"locks.plugin.d.ts","sourceRoot":"","sources":["../src/locks.plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAqBrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,WAAY,YAAW,aAAa;IAOnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,OAAO,WAAW;IAC3B,QAAQ,CAAC,WAAW,gEAAgE;IAEpF,OAAO,CAAC,YAAY,CAAC,CAA2C;gBAEnC,OAAO,GAAE,mBAAwB;IAE9D,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,GAAG,WAAW;IAMzF,OAAO,CAAC,MAAM,CAAC,aAAa;IAU5B,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,gBAAgB,CAAC;IAIrE,YAAY,IAAI,QAAQ,EAAE;IAsC1B,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CAGhD"}
1
+ {"version":3,"file":"locks.plugin.d.ts","sourceRoot":"","sources":["../src/locks.plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAqBrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,WAAY,YAAW,aAAa;IAOnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAW;IACnC,QAAQ,CAAC,WAAW,gEAAgE;IAEpF,OAAO,CAAC,YAAY,CAAC,CAA2C;gBAEnC,OAAO,GAAE,mBAAwB;IAE9D,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,GAAG,WAAW;IAMzF,OAAO,CAAC,MAAM,CAAC,aAAa;IAU5B,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,gBAAgB,CAAC;IAIrE,YAAY,IAAI,QAAQ,EAAE;IAsC1B,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CAGhD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestjs-redisx/locks",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Distributed locks plugin for NestJS RedisX with auto-renewal and retry strategies",
5
5
  "author": "NestJS RedisX Team",
6
6
  "license": "MIT",