1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import { Queue
} from
'mnemonist';
5 import { Constants
} from
'./Constants.js';
7 export enum AsyncLockType
{
8 configuration
= 'configuration',
9 performance
= 'performance',
12 type ResolveType
= (value
: void | PromiseLike
<void>) => void;
14 export class AsyncLock
{
15 private static readonly asyncLocks
= new Map
<AsyncLockType
, AsyncLock
>();
16 private acquired
: boolean;
17 private readonly resolveQueue
: Queue
<ResolveType
>;
19 private constructor() {
20 this.acquired
= false;
21 this.resolveQueue
= new Queue
<ResolveType
>();
24 public static async runExclusive
<T
>(type: AsyncLockType
, fn
: () => T
| Promise
<T
>): Promise
<T
> {
25 return AsyncLock
.acquire(type)
28 AsyncLock
.release(type).catch(Constants
.EMPTY_FUNCTION
);
32 private static async acquire(type: AsyncLockType
): Promise
<void> {
33 const asyncLock
= AsyncLock
.getAsyncLock(type);
34 if (!asyncLock
.acquired
) {
35 asyncLock
.acquired
= true;
38 return new Promise
<void>((resolve
) => {
39 asyncLock
.resolveQueue
.enqueue(resolve
);
43 private static async release(type: AsyncLockType
): Promise
<void> {
44 const asyncLock
= AsyncLock
.getAsyncLock(type);
45 if (asyncLock
.resolveQueue
.size
=== 0 && asyncLock
.acquired
) {
46 asyncLock
.acquired
= false;
49 const queuedResolve
= asyncLock
.resolveQueue
.dequeue()!;
50 return new Promise
<void>((resolve
) => {
56 private static getAsyncLock(type: AsyncLockType
): AsyncLock
{
57 if (!AsyncLock
.asyncLocks
.has(type)) {
58 AsyncLock
.asyncLocks
.set(type, new AsyncLock());
60 return AsyncLock
.asyncLocks
.get(type)!;