node-apparatus
Version:
A mix of common components needed for awesome node experience
91 lines • 3.46 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SequentialInvocationQueue = void 0;
const spin_wait_lock_1 = require("../spin-wait-lock/spin-wait-lock");
/**
* A class that allows for the sequential invocation of a function.
*/
class SequentialInvocationQueue {
/**
* @param lock The lock to used for synchronization.
* @param invocationFunction The function to invoke.
* @param maxQueueLength The maximum length of the queue.
*/
constructor(lock = new spin_wait_lock_1.SpinWaitLock(), invocationFunction, maxQueueLength = Number.MAX_SAFE_INTEGER) {
this.lock = lock;
this.invocationFunction = invocationFunction;
this.maxQueueLength = maxQueueLength;
this.invocationQueue = new Array();
}
/**
* Invokes the function with the given arguments, if an execution is already underway en-ques the current invocation.
* @param args The arguments to pass to the invocationFunction.
* @param spinTime The time to wait between attempts to acquire the lock.
* @param index The index to replace in the queue, if an execution is already active.
* @returns A promise that resolves to the result of the invocation.
*/
async invoke(args, spinTime = 100, index = undefined) {
if (this.invocationQueue.length >= this.maxQueueLength)
return { state: "error:queue-full" };
if (index !== undefined) {
this.invocationQueue[index] = args;
}
else {
this.invocationQueue.push(args);
}
try {
const lockResult = await this.lock.acquire(spinTime, () => this.invocationQueue.length <= 0);
if (lockResult === spin_wait_lock_1.SpinWaitLockState.Condition) {
return { state: "error:queue-empty" };
}
else {
if (this.invocationQueue.length === 0)
return { state: "error:queue-empty" };
const invocationParams = this.invocationQueue.shift();
const result = await this.invocationFunction(invocationParams);
return { result, state: "success" };
}
}
finally {
this.lock.release();
}
}
/**
* Deletes the invocation at the given index.
* @param index The index of the invocation to delete.
* @returns void
*/
delete(index) {
this.invocationQueue.splice(index, 1);
}
/**
* Returns an iterator for the invocation queue.
* @returns An iterator for the invocation queue.
* @example
* ```typescript
* const invocationQueue = new SequentialInvocationQueue<number[], void>(new SpinWaitLock(), sensitiveWork);
* invocationQueue.invoke([undefined, 0]);
* invocationQueue.invoke([undefined, 1]);
* invocationQueue.invoke([undefined, 2]);
* for (const invocation of invocationQueue) {
* console.log(invocation);
* }
* ```
*/
[Symbol.iterator]() {
return this.invocationQueue[Symbol.iterator]();
}
/**
* Clears the invocation queue.
* @returns void
*/
clear() {
this.invocationQueue.length = 0;
}
[Symbol.asyncDispose]() {
this.invocationQueue.length = 0;
this.lock.release();
}
}
exports.SequentialInvocationQueue = SequentialInvocationQueue;
//# sourceMappingURL=sequential-invocation-queue.js.map