UNPKG

@azure/core-amqp

Version:

Common library for amqp based azure sdks like @azure/event-hubs.

159 lines (158 loc) 5.55 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var lock_exports = {}; __export(lock_exports, { CancellableAsyncLockImpl: () => CancellableAsyncLockImpl }); module.exports = __toCommonJS(lock_exports); var import_abort_controller = require("@azure/abort-controller"); var import_rhea_promise = require("rhea-promise"); var import_constants = require("./constants.js"); var import_log = require("../log.js"); class CancellableAsyncLockImpl { _keyMap = /* @__PURE__ */ new Map(); _executionRunningSet = /* @__PURE__ */ new Set(); /** * Returns a promise that resolves to the value returned by the provided task function. * Only 1 task can be invoked at a time for a given `key` value. * * An acquire call can be cancelled via an `abortSignal`. * If cancelled, the promise will be rejected with an `AbortError`. * * `acquireTimeoutInMs` can also be provided to properties. * If the timeout is reached before the provided `task` is invoked, * then the promise will be rejected with an Error stating the task * timed out waiting to acquire a lock. * * @param key - All `acquire` calls are grouped by the provided `key`. * @param task - The function to invoke once the lock has been acquired. * @param properties - Additional properties to control the behavior of `acquire`. */ acquire(key, task, properties) { const { abortSignal, timeoutInMs } = properties; if (abortSignal?.aborted) { return Promise.reject(new import_abort_controller.AbortError(import_constants.StandardAbortMessage)); } const taskQueue = this._keyMap.get(key) ?? []; this._keyMap.set(key, taskQueue); const { promise, rejecter, resolver } = getPromiseParts(); const taskDetails = { reject: rejecter, resolve: resolver, task }; if (typeof timeoutInMs === "number") { const tid = setTimeout( () => { this._removeTaskDetails(key, taskDetails); rejecter( new import_rhea_promise.OperationTimeoutError(`The task timed out waiting to acquire a lock for ${key}`) ); }, Math.max(timeoutInMs, 0) ); taskDetails.tid = tid; } if (abortSignal) { const abortListener = () => { this._removeTaskDetails(key, taskDetails); rejecter(new import_abort_controller.AbortError(import_constants.StandardAbortMessage)); }; abortSignal.addEventListener("abort", abortListener); taskDetails.abortSignal = abortSignal; taskDetails.abortListener = abortListener; } taskQueue.push(taskDetails); import_log.logger.verbose( `Called acquire() for lock "${key}". Lock "${key}" has ${taskQueue.length} pending tasks.` ); this._execute(key); return promise; } /** * Iterates over all the pending tasks for a given `key` serially. * * Note: If the pending tasks are already being iterated by an early * _execute invocation, this returns immediately. * @returns */ async _execute(key) { if (this._executionRunningSet.has(key)) { return; } const taskQueue = this._keyMap.get(key); if (!taskQueue || !taskQueue.length) { return; } this._executionRunningSet.add(key); while (taskQueue.length) { const taskDetails = taskQueue.shift(); if (!taskDetails) { continue; } try { import_log.logger.verbose(`Acquired lock for "${key}", invoking task.`); cleanupTaskDetails(taskDetails); const value = await taskDetails.task(); taskDetails.resolve(value); } catch (err) { taskDetails.reject(err); } import_log.logger.verbose( `Task completed for lock "${key}". Lock "${key}" has ${taskQueue.length} pending tasks.` ); } this._executionRunningSet.delete(key); this._keyMap.delete(key); } _removeTaskDetails(key, taskDetails) { const taskQueue = this._keyMap.get(key); if (!taskQueue || !taskQueue.length) { return; } const index = taskQueue.indexOf(taskDetails); if (index !== -1) { const [details] = taskQueue.splice(index, 1); cleanupTaskDetails(details); } } } function getPromiseParts() { let resolver; let rejecter; const promise = new Promise((resolve, reject) => { resolver = resolve; rejecter = reject; }); return { promise, resolver, rejecter }; } function cleanupTaskDetails(taskDetails) { if (taskDetails.tid) clearTimeout(taskDetails.tid); if (taskDetails.abortSignal && taskDetails.abortListener) { taskDetails.abortSignal.removeEventListener("abort", taskDetails.abortListener); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CancellableAsyncLockImpl }); //# sourceMappingURL=lock.js.map