/// import { EventEmitter } from "events"; import { Redis as IORedisClient, Cluster as IORedisCluster } from "ioredis"; declare type Client = IORedisClient | IORedisCluster; export declare type ClientExecutionResult = { client: Client; vote: "for"; value: number; } | { client: Client; vote: "against"; error: Error; }; export declare type ExecutionStats = { readonly membershipSize: number; readonly quorumSize: number; readonly votesFor: Set; readonly votesAgainst: Map; }; export declare type ExecutionResult = { attempts: ReadonlyArray>; }; /** * */ export interface Settings { readonly driftFactor: number; readonly retryCount: number; readonly retryDelay: number; readonly retryJitter: number; readonly automaticExtensionThreshold: number; } export declare class ResourceLockedError extends Error { readonly message: string; constructor(message: string); } export declare class ExecutionError extends Error { readonly message: string; readonly attempts: ReadonlyArray>; constructor(message: string, attempts: ReadonlyArray>); } export declare class Lock { readonly redlock: Redlock; readonly resources: string[]; readonly value: string; readonly attempts: ReadonlyArray>; expiration: number; constructor(redlock: Redlock, resources: string[], value: string, attempts: ReadonlyArray>, expiration: number); release(): Promise; extend(duration: number): Promise; } export declare type RedlockAbortSignal = AbortSignal & { error?: Error; }; /** * A redlock object is instantiated with an array of at least one redis client * and an optional `options` object. Properties of the Redlock object should NOT * be changed after it is first used, as doing so could have unintended * consequences for live locks. */ export default class Redlock extends EventEmitter { readonly clients: Set; readonly settings: Settings; readonly scripts: { readonly acquireScript: { value: string; hash: string; }; readonly extendScript: { value: string; hash: string; }; readonly releaseScript: { value: string; hash: string; }; }; constructor(clients: Iterable, settings?: Partial, scripts?: { readonly acquireScript?: string | ((script: string) => string); readonly extendScript?: string | ((script: string) => string); readonly releaseScript?: string | ((script: string) => string); }); /** * Generate a sha1 hash compatible with redis evalsha. */ private _hash; /** * Generate a cryptographically random string. */ private _random; /** * This method runs `.quit()` on all client connections. */ quit(): Promise; /** * This method acquires a locks on the resources for the duration specified by * the `duration`. */ acquire(resources: string[], duration: number, settings?: Partial): Promise; /** * This method unlocks the provided lock from all servers still persisting it. * It will fail with an error if it is unable to release the lock on a quorum * of nodes, but will make no attempt to restore the lock in the case of a * failure to release. It is safe to re-attempt a release or to ignore the * error, as the lock will automatically expire after its timeout. */ release(lock: Lock, settings?: Partial): Promise; /** * This method extends a valid lock by the provided `duration`. */ extend(existing: Lock, duration: number, settings?: Partial): Promise; /** * Execute a script on all clients. The resulting promise is resolved or * rejected as soon as this quorum is reached; the resolution or rejection * will contains a `stats` property that is resolved once all votes are in. */ private _execute; private _attemptOperation; private _attemptOperationOnClient; /** * Wrap and execute a routine in the context of an auto-extending lock, * returning a promise of the routine's value. In the case that auto-extension * fails, an AbortSignal will be updated to indicate that abortion of the * routine is in order, and to pass along the encountered error. * * @example * ```ts * await redlock.using([senderId, recipientId], 5000, { retryCount: 5 }, async (signal) => { * const senderBalance = await getBalance(senderId); * const recipientBalance = await getBalance(recipientId); * * if (senderBalance < amountToSend) { * throw new Error("Insufficient balance."); * } * * // The abort signal will be true if: * // 1. the above took long enough that the lock needed to be extended * // 2. redlock was unable to extend the lock * // * // In such a case, exclusivity can no longer be guaranteed for further * // operations, and should be handled as an exceptional case. * if (signal.aborted) { * throw signal.error; * } * * await setBalances([ * {id: senderId, balance: senderBalance - amountToSend}, * {id: recipientId, balance: recipientBalance + amountToSend}, * ]); * }); * ``` */ using(resources: string[], duration: number, settings: Partial, routine?: (signal: RedlockAbortSignal) => Promise): Promise; using(resources: string[], duration: number, routine: (signal: RedlockAbortSignal) => Promise): Promise; } export {};