UNPKG

@imqueue/rpc

Version:

RPC-like client-service implementation over messaging queue

118 lines (117 loc) 3.77 kB
/*! * IMQLock implementation * * I'm Queue Software Project * Copyright (C) 2025 imqueue.com <support@imqueue.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * If you want to use this code in a closed source (commercial) project, you can * purchase a proprietary commercial license. Please contact us at * <support@imqueue.com> to get commercial licensing options. */ import { ILogger } from '@imqueue/core'; export type AcquiredLock<T> = T | boolean; export type IMQLockTask = [(...args: any[]) => any, (...args: any[]) => any]; export type IMQLockQueue = Array<IMQLockTask>; export interface IMQLockMetadataItem { className: string; methodName: string | symbol; args: any[]; } export interface IMQLockMetadata { [key: string]: IMQLockMetadataItem; } /** * Class IMQLock. * Implements promise-based locks. * * @example * ~~~typescript * import { IMQLock, AcquiredLock } from '.'; * * async function doSomething(): Promise<number | AcquiredLock<number>> { * const lock: AcquiredLock<number> = await IMQLock.acquire<number>('doSomething'); * * if (IMQLock.locked('doSomething')) { * // avoiding err handling in this way can cause ded-locks * // so it is good always try catch locked calls! * // BTW, IMQLock uses timeouts to avoid dead-locks * try { * // this code will be called only once per multiple async calls * // so all promises will be resolved with the same value * const res = Math.random(); * IMQLock.release('doSomething', res); * return res; * } * * catch (err) { * // release acquired locks with error * IMQLock.release('doSomething', null, err); * throw err; * } * } * * return lock; * } * * (async () => { * for (let i = 0; i < 10; ++i) { * // run doSomething() asynchronously 10 times * doSomething().then((res) => console.log(res)); * } * })(); * ~~~ */ export declare class IMQLock { private static acquiredLocks; private static queues; private static metadata; /** * Deadlock timeout in milliseconds * * @type {number} */ static deadlockTimeout: number; /** * Logger used to log errors which appears during locked calls * * @type {ILogger} */ static logger: ILogger; /** * Acquires a lock for a given key * * @param {string} key * @param {(...args: any[]) => any} [callback] * @param {IMQLockMetadataItem} [metadata] * @returns {AcquiredLock} */ static acquire<T>(key: string, callback?: (...args: any[]) => any, metadata?: IMQLockMetadataItem): Promise<AcquiredLock<T>>; /** * Releases previously acquired lock for a given key * * @param {string} key * @param {T} value * @param {E} err */ static release<T, E>(key: string, value?: T, err?: E): void; /** * Returns true if given key is locked, false otherwise * * @param {string} key * @returns {boolean} */ static locked(key: string): boolean; }