hamok
Version:
Lightweight Distributed Object Storage on RAFT consensus algorithm
66 lines (46 loc) • 1.43 kB
text/typescript
import { createLogger } from './logger';
type OngoingProcess = () => Promise<unknown>;
const logger = createLogger('ConcurrentExecutor');
export class ConcurrentExecutor {
private _parked: OngoingProcess[] = [];
private _tasks: OngoingProcess[] = [];
private _semaphore: number;
public constructor(
public readonly maxConcurrencyLevel: number
) {
if (maxConcurrencyLevel < 1) throw new Error('maxConcurrencyLevel must be greater than 0');
this._semaphore = maxConcurrencyLevel;
this.postProcess = this.postProcess.bind(this);
}
public execute<T = unknown>(action: () => Promise<T>, park = false): Promise<T> {
return new Promise<T>((resolve, reject) => {
const task = () => action().then(resolve)
.catch(reject);
if (park) this._parked.push(task);
else this._tasks.push(task);
this._run();
});
}
public flushParkedActions() {
this._tasks.push(...this._parked);
this._parked = [];
this._run();
}
private postProcess() {
++this._semaphore;
if (this._semaphore > this.maxConcurrencyLevel) {
logger.warn('Semaphore is greater than maxConcurrencyLevel');
this._semaphore = this.maxConcurrencyLevel;
}
this._run();
}
private _run() {
if (this._tasks.length === 0 || this._semaphore === 0) return;
const task = this._tasks.shift();
if (!task) return;
--this._semaphore;
task()
.then(() => this.postProcess())
.catch(this.postProcess);
}
}