@push.rocks/lik
Version:
Provides a collection of lightweight helpers and utilities for Node.js projects.
166 lines • 12.5 kB
JavaScript
import * as plugins from './classes.plugins.js';
export class AsyncExecutionStack {
executionSlots = [];
isProcessing = false;
/** Maximum concurrent non-exclusive tasks (Infinity = unlimited) */
nonExclusiveMaxConcurrency = Infinity;
/** Currently running non-exclusive task count */
nonExclusiveCurrentCount = 0;
/** Queue of resolvers waiting for a non-exclusive slot */
nonExclusivePendingQueue = [];
async getExclusiveExecutionSlot(funcArg, timeoutArg) {
const executionDeferred = plugins.smartpromise.defer();
const executionSlot = {
funcToExecute: funcArg,
executionDeferred,
timeout: timeoutArg,
mode: 'exclusive',
};
this.executionSlots.push(executionSlot);
this.processExecutionSlots();
return executionDeferred.promise;
}
async getNonExclusiveExecutionSlot(funcArg, timeoutArg) {
const executionDeferred = plugins.smartpromise.defer();
const executionSlot = {
funcToExecute: funcArg,
executionDeferred,
timeout: timeoutArg,
mode: 'nonexclusive',
};
this.executionSlots.push(executionSlot);
this.processExecutionSlots();
return executionDeferred.promise;
}
/**
* Set the maximum number of concurrent non-exclusive tasks.
* @param concurrency minimum 1 (Infinity means unlimited)
*/
setNonExclusiveMaxConcurrency(concurrency) {
if (!Number.isFinite(concurrency) || concurrency < 1) {
throw new Error('nonExclusiveMaxConcurrency must be a finite number >= 1');
}
this.nonExclusiveMaxConcurrency = concurrency;
}
/** Get the configured max concurrency for non-exclusive tasks */
getNonExclusiveMaxConcurrency() {
return this.nonExclusiveMaxConcurrency;
}
/** Number of non-exclusive tasks currently running */
getActiveNonExclusiveCount() {
return this.nonExclusiveCurrentCount;
}
/** Number of non-exclusive tasks waiting for a free slot */
getPendingNonExclusiveCount() {
return this.nonExclusivePendingQueue.length;
}
async processExecutionSlots() {
if (this.isProcessing) {
return;
}
this.isProcessing = true;
while (this.executionSlots.length > 0) {
const currentSlot = this.executionSlots[0];
if (currentSlot.mode === 'exclusive') {
await this.executeExclusiveSlot(currentSlot);
this.executionSlots.shift();
}
else {
// Gather all non-exclusive slots at the front of the queue
const nonExclusiveSlots = [];
while (this.executionSlots.length > 0 && this.executionSlots[0].mode === 'nonexclusive') {
nonExclusiveSlots.push(this.executionSlots.shift());
}
await this.executeNonExclusiveSlots(nonExclusiveSlots);
}
}
this.isProcessing = false;
}
async executeExclusiveSlot(slot) {
try {
if (slot.timeout) {
const timeoutInstance = new plugins.smartdelay.Timeout(slot.timeout);
try {
const result = await Promise.race([
slot.funcToExecute(),
timeoutInstance.promise.then(() => {
throw new Error('Timeout reached');
}),
]);
timeoutInstance.cancel();
slot.executionDeferred.resolve(result);
}
catch (error) {
timeoutInstance.cancel();
throw error;
}
}
else {
const result = await slot.funcToExecute();
slot.executionDeferred.resolve(result);
}
}
catch (error) {
slot.executionDeferred.reject(error);
}
}
async executeNonExclusiveSlots(slots) {
const promises = slots.map(async (slot) => {
// wait for an available non-exclusive slot
await this.waitForNonExclusiveSlot();
try {
// execute with optional timeout
if (slot.timeout) {
const timeoutInstance = new plugins.smartdelay.Timeout(slot.timeout);
try {
const result = await Promise.race([
slot.funcToExecute(),
timeoutInstance.promise.then(() => { throw new Error('Timeout reached'); }),
]);
timeoutInstance.cancel();
slot.executionDeferred.resolve(result);
}
catch (error) {
timeoutInstance.cancel();
throw error;
}
}
else {
const result = await slot.funcToExecute();
slot.executionDeferred.resolve(result);
}
}
catch (error) {
slot.executionDeferred.reject(error);
}
finally {
this.releaseNonExclusiveSlot();
}
});
await Promise.all(promises);
}
/**
* Wait until a non-exclusive slot is available (respects max concurrency).
*/
waitForNonExclusiveSlot() {
if (this.nonExclusiveCurrentCount < this.nonExclusiveMaxConcurrency) {
this.nonExclusiveCurrentCount++;
return Promise.resolve();
}
return new Promise((resolve) => {
this.nonExclusivePendingQueue.push(() => {
this.nonExclusiveCurrentCount++;
resolve();
});
});
}
/** Release a non-exclusive slot and wake the next waiter, if any. */
releaseNonExclusiveSlot() {
this.nonExclusiveCurrentCount--;
const next = this.nonExclusivePendingQueue.shift();
if (next) {
next();
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hc3luY2V4ZWN1dGlvbnN0YWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5hc3luY2V4ZWN1dGlvbnN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sc0JBQXNCLENBQUM7QUFTaEQsTUFBTSxPQUFPLG1CQUFtQjtJQUN0QixjQUFjLEdBQTBCLEVBQUUsQ0FBQztJQUMzQyxZQUFZLEdBQUcsS0FBSyxDQUFDO0lBQzdCLG9FQUFvRTtJQUM1RCwwQkFBMEIsR0FBVyxRQUFRLENBQUM7SUFDdEQsaURBQWlEO0lBQ3pDLHdCQUF3QixHQUFXLENBQUMsQ0FBQztJQUM3QywwREFBMEQ7SUFDbEQsd0JBQXdCLEdBQXNCLEVBQUUsQ0FBQztJQUVsRCxLQUFLLENBQUMseUJBQXlCLENBQ3BDLE9BQXlCLEVBQ3pCLFVBQW1CO1FBRW5CLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUssQ0FBQztRQUMxRCxNQUFNLGFBQWEsR0FBc0I7WUFDdkMsYUFBYSxFQUFFLE9BQU87WUFDdEIsaUJBQWlCO1lBQ2pCLE9BQU8sRUFBRSxVQUFVO1lBQ25CLElBQUksRUFBRSxXQUFXO1NBQ2xCLENBQUM7UUFDRixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUM3QixPQUFPLGlCQUFpQixDQUFDLE9BQU8sQ0FBQztJQUNuQyxDQUFDO0lBRU0sS0FBSyxDQUFDLDRCQUE0QixDQUN2QyxPQUF5QixFQUN6QixVQUFtQjtRQUVuQixNQUFNLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFLLENBQUM7UUFDMUQsTUFBTSxhQUFhLEdBQXNCO1lBQ3ZDLGFBQWEsRUFBRSxPQUFPO1lBQ3RCLGlCQUFpQjtZQUNqQixPQUFPLEVBQUUsVUFB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