2026-05-10 13:12:44 +08:00

155 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// exe-engine/src/controller/scheduler-v2.js
// EXE-Engine · 调度器 v2
// 优先队列 + 依赖图的增强调度
// PRJ-EXE-001 · Phase 1 · ZY-EXE-P1-005
// 版权:国作登字-2026-A-00037559
'use strict';
const { randomUUID } = require('crypto');
// 优先级数值映射数值越小优先级越高high=0 最先出队)
const PRIORITY_MAP = { high: 0, normal: 1, low: 2 };
/**
* 调度器 v2
*
* 本体论锚定:调度器 = 笔的时间管理器。
* 哪些字先写、哪些字后写、哪些字要等前面的字写完才能写,
* 调度器用优先队列和依赖图来决定。
*/
class SchedulerV2 {
/**
* @param {object} deps
* @param {AgentController} deps.agentController Agent 调度器
* @param {number} [deps.maxConcurrency=3] 最大并发数
*/
constructor(deps = {}) {
this._agentController = deps.agentController || null;
this._maxConcurrency = deps.maxConcurrency || 3;
// 待处理队列
this._queue = [];
// 已完成任务 { taskId: result }
this._completed = new Map();
// 失败任务 { taskId: error }
this._failed = new Map();
// 正在执行的任务
this._running = new Set();
}
/**
* 入队任务
* @param {object} task
* @param {string} [task.taskId] 任务 ID自动生成
* @param {string} task.agentId Agent ID
* @param {string} [task.priority='normal'] 优先级
* @param {string[]} [task.dependsOn=[]] 依赖任务 ID 列表
* @param {object} task.payload 任务载荷
* @returns {string} taskId
*/
enqueue(task) {
const taskId = task.taskId || `task-${randomUUID().slice(0, 8)}`;
const entry = {
taskId,
agentId: task.agentId,
priority: task.priority || 'normal',
dependsOn: task.dependsOn || [],
payload: task.payload || {},
status: 'pending',
enqueuedAt: new Date().toISOString()
};
this._queue.push(entry);
// 按优先级排序(同优先级保持 FIFO
this._queue.sort((a, b) => {
const pa = PRIORITY_MAP[a.priority] ?? 1;
const pb = PRIORITY_MAP[b.priority] ?? 1;
return pa - pb;
});
return taskId;
}
/**
* 出队:返回优先级最高且依赖已满足的任务
* @returns {object|null}
*/
dequeue() {
for (let i = 0; i < this._queue.length; i++) {
const task = this._queue[i];
if (this._areDependenciesMet(task)) {
this._queue.splice(i, 1);
task.status = 'running';
this._running.add(task.taskId);
return task;
}
}
return null;
}
/**
* 标记任务完成
* @param {string} taskId
* @param {*} result 执行结果
*/
complete(taskId, result) {
this._completed.set(taskId, {
result,
completedAt: new Date().toISOString()
});
this._running.delete(taskId);
}
/**
* 标记任务失败
* @param {string} taskId
* @param {string} error 错误信息
*/
fail(taskId, error) {
this._failed.set(taskId, {
error,
failedAt: new Date().toISOString()
});
this._running.delete(taskId);
}
/**
* 获取当前队列状态
* @returns {object[]}
*/
getQueue() {
return [...this._queue];
}
/**
* 获取调度器指标
* @returns {object}
*/
getStatus() {
return {
pending: this._queue.length,
running: this._running.size,
completed: this._completed.size,
failed: this._failed.size,
maxConcurrency: this._maxConcurrency
};
}
// ── 内部方法 ──
/**
* 检查任务依赖是否全部满足
* @param {object} task
* @returns {boolean}
*/
_areDependenciesMet(task) {
if (!task.dependsOn || task.dependsOn.length === 0) return true;
return task.dependsOn.every(depId => this._completed.has(depId));
}
}
module.exports = SchedulerV2;