1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import Queue from
'mnemonist/queue.js'
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 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
22 this.resolveQueue
= new Queue
<ResolveType
>()
25 public static async runExclusive
<T
>(type: AsyncLockType
, fn
: () => T
| Promise
<T
>): Promise
<T
> {
26 return await AsyncLock
.acquire(type)
29 AsyncLock
.release(type).catch(Constants
.EMPTY_FUNCTION
)
33 private static async acquire (type: AsyncLockType
): Promise
<void> {
34 const asyncLock
= AsyncLock
.getAsyncLock(type)
35 if (!asyncLock
.acquired
) {
36 asyncLock
.acquired
= true
39 await new Promise
<void>((resolve
) => {
40 // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
41 asyncLock
.resolveQueue
.enqueue(resolve
)
45 private static async release (type: AsyncLockType
): Promise
<void> {
46 const asyncLock
= AsyncLock
.getAsyncLock(type)
47 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
48 if (asyncLock
.resolveQueue
.size
=== 0 && asyncLock
.acquired
) {
49 asyncLock
.acquired
= false
52 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
53 const queuedResolve
= asyncLock
.resolveQueue
.dequeue()!
54 await new Promise
<void>((resolve
) => {
55 // eslint-disable-next-line @typescript-eslint/no-unsafe-call
61 private static getAsyncLock (type: AsyncLockType
): AsyncLock
{
62 if (!AsyncLock
.asyncLocks
.has(type)) {
63 AsyncLock
.asyncLocks
.set(type, new AsyncLock())
65 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
66 return AsyncLock
.asyncLocks
.get(type)!