UNPKG

@devlearning/mutex-fast-lock

Version:

Mutex fast lock localstorage

1 lines 16.7 kB
{"version":3,"file":"devlearning-mutex-fast-lock.mjs","sources":["../../../projects/mutex-fast-lock/src/lib/models/mutex-fast-lock-config.ts","../../../projects/mutex-fast-lock/src/lib/models/mutex-lock-stats.ts","../../../projects/mutex-fast-lock/src/lib/mutex-fast-lock-config.injector.ts","../../../projects/mutex-fast-lock/src/lib/models/lock-item.ts","../../../projects/mutex-fast-lock/src/lib/mutex-fast-lock.service.ts","../../../projects/mutex-fast-lock/src/lib/mutex-fast-lock.module.ts","../../../projects/mutex-fast-lock/src/public-api.ts","../../../projects/mutex-fast-lock/src/devlearning-mutex-fast-lock.ts"],"sourcesContent":["export class MutexFastLockConfig{\r\n lockPrefix: string;\r\n timeout: number;\r\n debugEnabled: boolean;\r\n}","export class MutexLockStats {\r\n restartCount: number;\r\n locksLost: number;\r\n contentionCount: number;\r\n acquireDuration: number;\r\n acquireStart: number;\r\n acquireEnd: number;\r\n lockStart: number;\r\n lockEnd: number;\r\n lockDuration: number;\r\n}","import { InjectionToken } from '@angular/core';\r\nimport { MutexFastLockConfig } from './models/mutex-fast-lock-config';\r\n\r\nexport const MUTEX_FAST_LOCK_CONFIG = new InjectionToken<MutexFastLockConfig>('MUTEX_FAST_LOCK_CONFIG');","export class LockItem{\r\n clientId: string;\r\n expiresAt: number;\r\n}","import { Inject, Injectable } from '@angular/core';\r\nimport { MUTEX_FAST_LOCK_CONFIG } from './mutex-fast-lock-config.injector';\r\nimport { MutexFastLockConfig } from './models/mutex-fast-lock-config';\r\nimport { MutexLockStats } from './models/mutex-lock-stats';\r\nimport { Observable, Subscriber } from 'rxjs';\r\nimport { LockItem } from './models/lock-item';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MutexFastLockService {\r\n\r\n private _clientId: string;\r\n private _xPrefix: string;\r\n private _yPrefix: string;\r\n\r\n constructor(\r\n @Inject(MUTEX_FAST_LOCK_CONFIG) private readonly _config: MutexFastLockConfig,\r\n ) {\r\n this._clientId = this._generateRandomId();\r\n this._xPrefix = _config.lockPrefix + '_X_';\r\n this._yPrefix = _config.lockPrefix + '_Y_';\r\n\r\n let that = this;\r\n window.addEventListener(\"beforeunload\", function (ev) {\r\n var arr = [];\r\n\r\n for (var i = 0; i < localStorage.length; i++) {\r\n if (localStorage.key(i).indexOf(that._xPrefix) == 0\r\n || localStorage.key(i).indexOf(that._yPrefix) == 0) {\r\n arr.push(localStorage.key(i));\r\n }\r\n }\r\n\r\n for (var i = 0; i < arr.length; i++) {\r\n localStorage.removeItem(arr[i]);\r\n }\r\n });\r\n }\r\n\r\n public lock(key: string, timeout: number = -1) {\r\n let that = this;\r\n\r\n if (timeout == -1) timeout = this._config.timeout;\r\n\r\n let xLock = that._xPrefix + key;\r\n let yLock = that._yPrefix + key;\r\n\r\n let lockStats: MutexLockStats = new MutexLockStats();\r\n\r\n that.resetStats(lockStats);\r\n\r\n this._config.debugEnabled ?? console.debug('Attempting to acquire Lock on \"%s\" using FastMutex instance \"%s\"', key, this._clientId);\r\n\r\n lockStats.acquireStart = new Date().getTime();\r\n\r\n //return new Promise(function (resolve, reject) {\r\n return new Observable<MutexLockStats>(subscriber => {\r\n // we need to differentiate between API calls to lock() and our internal\r\n // recursive calls so that we can timeout based on the original lock() and\r\n // not each subsequent call. Therefore, create a new function here within\r\n // the promise closure that we use for subsequent calls:\r\n let acquireLock = function acquireLock(key) {\r\n\r\n that._releaseExpiredLock(xLock);\r\n that._releaseExpiredLock(yLock);\r\n\r\n var elapsedTime = new Date().getTime() - lockStats.acquireStart;\r\n if (elapsedTime >= timeout) {\r\n that._config.debugEnabled ?? console.debug('Lock on \"%s\" could not be acquired within %sms by FastMutex client \"%s\"', key, timeout, that._clientId);\r\n subscriber.error(new Error('Lock could not be acquired within ' + timeout + 'ms'));\r\n }\r\n\r\n that._setItem(xLock, that._clientId, timeout);\r\n\r\n // if y exists, another client is getting a lock, so retry in a bit\r\n var lsY = that._getItem(yLock, timeout);\r\n if (lsY) {\r\n that._config.debugEnabled ?? console.debug('Lock exists on Y (%s), restarting...', lsY);\r\n lockStats.restartCount++;\r\n setTimeout(function () {\r\n return acquireLock(key);\r\n }, 10);\r\n return;\r\n }\r\n\r\n // ask for inner lock\r\n that._setItem(yLock, that._clientId, timeout);\r\n\r\n // if x was changed, another client is contending for an inner lock\r\n var lsX = that._getItem(xLock, timeout);\r\n if (lsX !== that._clientId) {\r\n lockStats.contentionCount++;\r\n that._config.debugEnabled ?? console.debug('Lock contention detected. X=\"%s\"', lsX);\r\n\r\n // Give enough time for critical section:\r\n setTimeout(function () {\r\n lsY = that._getItem(yLock, timeout);\r\n if (lsY === that._clientId) {\r\n // we have a lock\r\n that._config.debugEnabled ?? console.debug('FastMutex client \"%s\" won the lock contention on \"%s\"', that._clientId, key);\r\n that.resolveWithStats(subscriber, lockStats);\r\n } else {\r\n // we lost the lock, restart the process again\r\n lockStats.restartCount++;\r\n lockStats.locksLost++;\r\n that._config.debugEnabled ?? console.debug('FastMutex client \"%s\" lost the lock contention on \"%s\" to another process (%s). Restarting...', that._clientId, key, lsY);\r\n setTimeout(function () {\r\n return acquireLock(key);\r\n }, 10);\r\n }\r\n }, 100);\r\n\r\n return;\r\n }\r\n\r\n // no contention:\r\n that._config.debugEnabled ?? console.debug('FastMutex client \"%s\" acquired a lock on \"%s\" with no contention', that._clientId, key);\r\n that.resolveWithStats(subscriber, lockStats);\r\n };\r\n\r\n acquireLock(key);\r\n\r\n });\r\n }\r\n\r\n public release(key) {\r\n this._config.debugEnabled ?? console.debug('FastMutex client \"%s\" is releasing lock on \"%s\"', this._clientId, key);\r\n\r\n let x = this._xPrefix + key;\r\n let y = this._yPrefix + key;\r\n localStorage.removeItem(x);\r\n localStorage.removeItem(y);\r\n\r\n //that.lockStats.lockEnd = new Date().getTime();\r\n //that.lockStats.lockDuration = that.lockStats.lockEnd - that.lockStats.lockStart;\r\n\r\n //let retStats = angular.copy(that.lockStats);\r\n\r\n //that.resetStats();\r\n\r\n //return retStats;\r\n }\r\n\r\n private _generateRandomId() {\r\n return Math.floor(Math.random() * 10000000000) + '';\r\n }\r\n\r\n private resetStats(lockStats: MutexLockStats) {\r\n lockStats.restartCount = 0;\r\n lockStats.locksLost = 0;\r\n lockStats.contentionCount = 0;\r\n lockStats.acquireDuration = 0;\r\n lockStats.acquireStart = null;\r\n }\r\n\r\n private resolveWithStats(subscriber: Subscriber<MutexLockStats>, stats: MutexLockStats) {\r\n var currentTime = new Date().getTime();\r\n stats.acquireEnd = currentTime;\r\n stats.acquireDuration = stats.acquireEnd - stats.acquireStart;\r\n stats.lockStart = currentTime;\r\n subscriber.next(stats);\r\n subscriber.complete();\r\n }\r\n\r\n /**\r\n * Helper function to wrap all values in an object that includes the time (so\r\n * that we can expire it in the future) and json.stringify's it\r\n */\r\n private _setItem(key, clientId, timeout) {\r\n let lockItem = new LockItem();\r\n lockItem.clientId = clientId;\r\n lockItem.expiresAt = new Date().getTime() + timeout;\r\n return localStorage.setItem(key, JSON.stringify(lockItem));\r\n }\r\n\r\n /**\r\n * Helper function to parse JSON encoded values set in localStorage\r\n */\r\n private _getItem(key, timeout) {\r\n var item = localStorage.getItem(key);\r\n\r\n if (!item) return null;\r\n\r\n var lockItem = <LockItem>JSON.parse(item);\r\n if (new Date().getTime() - lockItem.expiresAt >= timeout) {\r\n this._config.debugEnabled ?? console.debug('FastMutex client \"%s\" removed an expired record on \"%s\"', this._clientId, key);\r\n localStorage.removeItem(key);\r\n return null;\r\n }\r\n\r\n return lockItem.clientId;\r\n }\r\n\r\n private _releaseExpiredLock(key: string){\r\n var item = localStorage.getItem(key);\r\n\r\n if (!item) return null;\r\n\r\n var lockItem = <LockItem>JSON.parse(item);\r\n\r\n if (lockItem.expiresAt <= new Date().getTime()) {\r\n this._config.debugEnabled ?? console.debug('FastMutex auto removed an expired record on \"%s\"', key);\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n}\r\n","import { ModuleWithProviders, NgModule } from \"@angular/core\";\r\nimport { MutexFastLockConfig } from \"./models/mutex-fast-lock-config\";\r\nimport { MUTEX_FAST_LOCK_CONFIG } from \"./mutex-fast-lock-config.injector\";\r\n\r\n@NgModule()\r\nexport class MutexFastLockModule {\r\n static forRoot(config: MutexFastLockConfig): ModuleWithProviders<MutexFastLockModule> {\r\n\r\n return ({\r\n ngModule: MutexFastLockModule,\r\n providers: [\r\n { provide: MUTEX_FAST_LOCK_CONFIG, useValue: config },\r\n ]\r\n });\r\n\r\n }\r\n}\r\n","/*\r\n * Public API Surface of cnet-mutex-fast-lock\r\n */\r\n\r\nexport * from './lib/models/mutex-fast-lock-config';\r\nexport * from './lib/models/mutex-lock-stats';\r\nexport * from './lib/mutex-fast-lock.service';\r\nexport * from './lib/mutex-fast-lock.module';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}