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 () {
21 this.resolveQueue
= new Queue
<ResolveType
>()
24 public static async runExclusive
<T
>(type: AsyncLockType
, fn
: () => T
| Promise
<T
>): Promise
<T
> {
25 return await 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 await 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 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
50 const queuedResolve
= asyncLock
.resolveQueue
.dequeue()!
51 await new Promise
<void>((resolve
) => {
57 private static getAsyncLock (type: AsyncLockType
): AsyncLock
{
58 if (!AsyncLock
.asyncLocks
.has(type)) {
59 AsyncLock
.asyncLocks
.set(type, new AsyncLock())
61 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
62 return AsyncLock
.asyncLocks
.get(type)!