X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Futils%2FAsyncLock.ts;h=fe984cebdef97d8043d0f29f6fb9ba99ec502f3c;hb=ee7c1da0e12c70134f31537a1c1e7040d309af5a;hp=53907ce46b723f246aa1bf0361f5986b727caf21;hpb=b9b617a2085713b870c8cfe3a5a65edbac1f8148;p=e-mobility-charging-stations-simulator.git diff --git a/src/utils/AsyncLock.ts b/src/utils/AsyncLock.ts index 53907ce4..fe984ceb 100644 --- a/src/utils/AsyncLock.ts +++ b/src/utils/AsyncLock.ts @@ -1,46 +1,62 @@ // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved. +import Queue from 'mnemonist/queue.js'; + +import { Constants } from './Constants'; + export enum AsyncLockType { configuration = 'configuration', performance = 'performance', } +type ResolveType = (value: void | PromiseLike) => void; + export class AsyncLock { - private static readonly instances = new Map(); + private static readonly asyncLocks = new Map(); private acquired: boolean; - private readonly resolveQueue: ((value: void | PromiseLike) => void)[]; + private readonly resolveQueue: Queue; - private constructor(private readonly type: AsyncLockType) { + private constructor() { this.acquired = false; - this.resolveQueue = []; + this.resolveQueue = new Queue(); } - public static getInstance(type: AsyncLockType): AsyncLock { - if (!AsyncLock.instances.has(type)) { - AsyncLock.instances.set(type, new AsyncLock(type)); - } - return AsyncLock.instances.get(type); + public static async runExclusive(type: AsyncLockType, fn: () => T | Promise): Promise { + return AsyncLock.acquire(type) + .then(fn) + .finally(() => { + AsyncLock.release(type).catch(Constants.EMPTY_FUNCTION); + }); } - public async acquire(): Promise { - if (!this.acquired) { - this.acquired = true; - } else { - return new Promise((resolve) => { - this.resolveQueue.push(resolve); - }); + private static async acquire(type: AsyncLockType): Promise { + const asyncLock = AsyncLock.getAsyncLock(type); + if (!asyncLock.acquired) { + asyncLock.acquired = true; + return; } + return new Promise((resolve) => { + asyncLock.resolveQueue.enqueue(resolve); + }); } - public async release(): Promise { - if (this.resolveQueue.length === 0 && this.acquired) { - this.acquired = false; + private static async release(type: AsyncLockType): Promise { + const asyncLock = AsyncLock.getAsyncLock(type); + if (asyncLock.resolveQueue.size === 0 && asyncLock.acquired) { + asyncLock.acquired = false; return; } - const queuedResolve = this.resolveQueue.shift(); - return new Promise((resolve) => { + const queuedResolve = asyncLock.resolveQueue.dequeue()!; + return new Promise((resolve) => { queuedResolve(); resolve(); }); } + + private static getAsyncLock(type: AsyncLockType): AsyncLock { + if (!AsyncLock.asyncLocks.has(type)) { + AsyncLock.asyncLocks.set(type, new AsyncLock()); + } + return AsyncLock.asyncLocks.get(type)!; + } }