@imqueue/rpc
Version:
RPC-like client-service implementation over messaging queue
118 lines (117 loc) • 3.77 kB
TypeScript
/*!
* 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;
}