diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 7f787c6d..cd237792 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -153,7 +153,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { await delay(5000) - if (!await placeholderResendCache.get(messageKey?.id!)) { + if (!(await placeholderResendCache.get(messageKey?.id!))) { logger.debug({ messageKey }, 'message received while resend requested') return 'RESOLVED' } diff --git a/src/Utils/make-mutex.ts b/src/Utils/make-mutex.ts index c7601568..13b34880 100644 --- a/src/Utils/make-mutex.ts +++ b/src/Utils/make-mutex.ts @@ -1,29 +1,11 @@ -export const makeMutex = () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let task = Promise.resolve() as Promise +import { Mutex as AsyncMutex } from 'async-mutex' - let taskTimeout: NodeJS.Timeout | undefined +export const makeMutex = () => { + const mutex = new AsyncMutex() return { mutex(code: () => Promise | T): Promise { - task = (async () => { - // wait for the previous task to complete - // if there is an error, we swallow so as to not block the queue - try { - await task - } catch {} - - try { - // execute the current task - const result = await code() - return result - } finally { - clearTimeout(taskTimeout) - } - })() - // we replace the existing task, appending the new piece of execution to it - // so the next task will have to wait for this one to finish - return task + return mutex.runExclusive(code) } } } @@ -31,15 +13,30 @@ export const makeMutex = () => { export type Mutex = ReturnType export const makeKeyedMutex = () => { - const map: { [id: string]: Mutex } = {} + const map = new Map() return { - mutex(key: string, task: () => Promise | T): Promise { - if (!map[key]) { - map[key] = makeMutex() + async mutex(key: string, task: () => Promise | T): Promise { + let entry = map.get(key) + + if (!entry) { + entry = { mutex: new AsyncMutex(), refCount: 0 } + map.set(key, entry) } - return map[key].mutex(task) + entry.refCount++ + + try { + return await entry.mutex.runExclusive(task) + } finally { + entry.refCount-- + // only delete it if this is still the current entry + if (entry.refCount === 0 && map.get(key) === entry) { + map.delete(key) + } + } } } } + +export type KeyedMutex = ReturnType