import type { Task } from './taskbuffer.classes.task.js'; import type { ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js'; export class TaskConstraintGroup = Record> { public name: string; public maxConcurrent: number; public cooldownMs: number; private constraintKeyForTask: (task: Task) => string | null | undefined; private runningCounts = new Map(); private lastCompletionTimes = new Map(); constructor(options: ITaskConstraintGroupOptions) { this.name = options.name; this.constraintKeyForTask = options.constraintKeyForTask; this.maxConcurrent = options.maxConcurrent ?? Infinity; this.cooldownMs = options.cooldownMs ?? 0; } public getConstraintKey(task: Task): 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(); } }