Files
taskbuffer/ts/taskbuffer.classes.taskconstraintgroup.ts

81 lines
2.5 KiB
TypeScript
Raw Normal View History

import type { Task } from './taskbuffer.classes.task.js';
import type { ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js';
export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<string, unknown>> {
public name: string;
public maxConcurrent: number;
public cooldownMs: number;
private constraintKeyForTask: (task: Task<any, any, TData>) => string | null | undefined;
private runningCounts = new Map<string, number>();
private lastCompletionTimes = new Map<string, number>();
constructor(options: ITaskConstraintGroupOptions<TData>) {
this.name = options.name;
this.constraintKeyForTask = options.constraintKeyForTask;
this.maxConcurrent = options.maxConcurrent ?? Infinity;
this.cooldownMs = options.cooldownMs ?? 0;
}
public getConstraintKey(task: Task<any, any, TData>): string | null {
const key = this.constraintKeyForTask(task);
return key ?? null;
}
public canRun(subGroupKey: string): boolean {
const running = this.runningCounts.get(subGroupKey) ?? 0;
if (running >= this.maxConcurrent) {
return false;
}
if (this.cooldownMs > 0) {
const lastCompletion = this.lastCompletionTimes.get(subGroupKey);
if (lastCompletion !== undefined) {
const elapsed = Date.now() - lastCompletion;
if (elapsed < this.cooldownMs) {
return false;
}
}
}
return true;
}
public acquireSlot(subGroupKey: string): void {
const current = this.runningCounts.get(subGroupKey) ?? 0;
this.runningCounts.set(subGroupKey, current + 1);
}
public releaseSlot(subGroupKey: string): void {
const current = this.runningCounts.get(subGroupKey) ?? 0;
const next = Math.max(0, current - 1);
if (next === 0) {
this.runningCounts.delete(subGroupKey);
} else {
this.runningCounts.set(subGroupKey, next);
}
this.lastCompletionTimes.set(subGroupKey, Date.now());
}
public getCooldownRemaining(subGroupKey: string): number {
if (this.cooldownMs <= 0) {
return 0;
}
const lastCompletion = this.lastCompletionTimes.get(subGroupKey);
if (lastCompletion === undefined) {
return 0;
}
const elapsed = Date.now() - lastCompletion;
return Math.max(0, this.cooldownMs - elapsed);
}
public getRunningCount(subGroupKey: string): number {
return this.runningCounts.get(subGroupKey) ?? 0;
}
public reset(): void {
this.runningCounts.clear();
this.lastCompletionTimes.clear();
}
}