/** * 任务调度器 * - FIFO 先进先出队列 * - 单线程执行(一次只执行一个任务) * - 去重:同一个 key 的任务如果已在队列中等待(未执行),则不重复添加 */ type Task = { key: string; execute: () => Promise; }; export class Scheduler { private queue: Task[] = []; private running = false; /** 当前在队列中等待执行的任务 key 集合(不含正在执行的) */ private pendingKeys = new Set(); /** * 添加任务 * @param key 任务唯一标识(如文件路径) * @param execute 任务执行函数 * @returns true 表示已加入队列;false 表示该 key 已存在,跳过 */ add(key: string, execute: () => Promise): boolean { if (this.pendingKeys.has(key)) { // 同一任务已在队列中,跳过 return false; } this.pendingKeys.add(key); this.queue.push({ key, execute }); // 触发执行(如果没有在跑的话) this._run(); return true; } private async _run() { if (this.running) return; this.running = true; while (this.queue.length > 0) { const task = this.queue.shift()!; // 任务开始执行前,从 pendingKeys 移除,允许后续同 key 任务重新入队 this.pendingKeys.delete(task.key); try { await task.execute(); } catch (err) { console.error(`[Scheduler] Task "${task.key}" failed:`, err); } } this.running = false; } /** 队列中等待执行的任务数量(不含正在执行的) */ get pendingCount(): number { return this.queue.length; } }