@imqueue/rpc
Version:
RPC-like client-service implementation over messaging queue
112 lines (111 loc) • 3.61 kB
TypeScript
/*!
* IMQLock implementation
*
* Copyright (c) 2018, imqueue.com <support@imqueue.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
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;
}