UNPKG

@push.rocks/lik

Version:

Provides a collection of lightweight helpers and utilities for Node.js projects.

166 lines 12.5 kB
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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