UNPKG

@imqueue/rpc

Version:

RPC-like client-service implementation over messaging queue

112 lines (111 loc) 3.61 kB
/*! * 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; }