248 lines
6.5 KiB
JavaScript
Raw Normal View History

/**
* core/task-queue 任务队列系统
*
* 任务结构
* task_id 唯一任务标识
* source 来源broadcast / maintenance / dev / auto
* type 类型system-task / dev-task / maintenance-task / auto-task
* priority 优先级high / normal / low
* status 状态pending / running / completed / failed
* executor 执行者zhuyuan
*
* 任务类型
* system-task 系统级任务广播状态同步
* dev-task 开发任务代码变更功能开发
* maintenance-task 维护任务结构修复文档更新
* auto-task 自动生成任务自检发现的问题
*
* 任务来源
* - Notion 广播
* - 系统维护任务
* - 开发任务
* - 自动开发循环生成
*
* 执行流程
* 任务进入队列 按优先级去重 执行器运行 执行结果写回
*
* 调用方式
* node core/task-queue [status|run|cleanup]
*/
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const QUEUE_PATH = path.join(ROOT, 'core/task-queue/queue.json');
/**
* 加载当前队列
*/
function loadQueue() {
if (!fs.existsSync(QUEUE_PATH)) {
return { version: '5.1', tasks: [], last_updated: null };
}
try {
return JSON.parse(fs.readFileSync(QUEUE_PATH, 'utf-8'));
} catch {
return { version: '5.1', tasks: [], last_updated: null };
}
}
/**
* 保存队列
*/
function saveQueue(queue) {
queue.last_updated = new Date().toISOString();
fs.writeFileSync(QUEUE_PATH, JSON.stringify(queue, null, 2), 'utf-8');
}
/**
* 添加任务到队列
*/
function enqueue(task) {
const queue = loadQueue();
// 去重:相同 task_id 只保留最新
const existing = queue.tasks.findIndex(t => t.task_id === task.task_id);
if (existing !== -1) {
const original = queue.tasks[existing];
queue.tasks[existing] = {
...original,
...task,
queued_at: original.queued_at,
updated_at: new Date().toISOString()
};
console.log(`🔄 更新已有任务: ${task.task_id}`);
} else {
queue.tasks.push({
...task,
queued_at: new Date().toISOString()
});
console.log(` 新增任务: ${task.task_id}`);
}
saveQueue(queue);
return task;
}
/**
* 批量入队
*/
function enqueueBatch(tasks) {
return tasks.map(t => enqueue(t));
}
/**
* 获取下一个待执行任务按优先级
*/
function dequeue() {
const queue = loadQueue();
const priorityOrder = { high: 0, normal: 1, low: 2 };
const pending = queue.tasks
.filter(t => t.status === 'pending')
.sort((a, b) => (priorityOrder[a.priority] || 1) - (priorityOrder[b.priority] || 1));
if (pending.length === 0) return null;
const task = pending[0];
task.status = 'running';
task.started_at = new Date().toISOString();
saveQueue(queue);
return task;
}
/**
* 标记任务完成
*/
function complete(taskId, result = null) {
const queue = loadQueue();
const task = queue.tasks.find(t => t.task_id === taskId);
if (!task) {
console.warn(`⚠️ 任务不存在: ${taskId}`);
return null;
}
task.status = 'completed';
task.completed_at = new Date().toISOString();
if (result) task.result = result;
saveQueue(queue);
console.log(`✅ 任务完成: ${taskId}`);
return task;
}
/**
* 标记任务失败
*/
function fail(taskId, error = null) {
const queue = loadQueue();
const task = queue.tasks.find(t => t.task_id === taskId);
if (!task) {
console.warn(`⚠️ 任务不存在: ${taskId}`);
return null;
}
task.status = 'failed';
task.failed_at = new Date().toISOString();
if (error) task.error = String(error);
saveQueue(queue);
console.log(`❌ 任务失败: ${taskId}`);
return task;
}
/**
* 获取队列状态
*/
function status() {
const queue = loadQueue();
const tasks = queue.tasks;
const stats = {
total: tasks.length,
pending: tasks.filter(t => t.status === 'pending').length,
running: tasks.filter(t => t.status === 'running').length,
completed: tasks.filter(t => t.status === 'completed').length,
failed: tasks.filter(t => t.status === 'failed').length,
last_updated: queue.last_updated,
by_type: {
'system-task': tasks.filter(t => t.type === 'system-task').length,
'dev-task': tasks.filter(t => t.type === 'dev-task').length,
'maintenance-task': tasks.filter(t => t.type === 'maintenance-task').length,
'auto-task': tasks.filter(t => t.type === 'auto-task').length,
'glada-task': tasks.filter(t => t.type === 'glada-task').length
}
};
return stats;
}
/**
* 清理已完成任务保留最近 50
*/
function cleanup() {
const queue = loadQueue();
const completed = queue.tasks.filter(t =>
t.status === 'completed' || t.status === 'failed'
);
if (completed.length > 50) {
const keep = completed
.sort((a, b) => (b.completed_at || b.failed_at || '').localeCompare(a.completed_at || a.failed_at || ''))
.slice(0, 50);
const keepIds = new Set(keep.map(t => t.task_id));
const active = queue.tasks.filter(t =>
t.status === 'pending' || t.status === 'running'
);
queue.tasks = [...active, ...keep];
saveQueue(queue);
console.log(`🧹 清理完成,保留 ${queue.tasks.length} 条任务`);
}
}
// CLI 入口
if (require.main === module) {
const cmd = process.argv[2] || 'status';
switch (cmd) {
case 'status': {
const s = status();
console.log('📊 任务队列状态:');
console.log(` 总计: ${s.total}`);
console.log(` 待处理: ${s.pending}`);
console.log(` 执行中: ${s.running}`);
console.log(` 已完成: ${s.completed}`);
console.log(` 失败: ${s.failed}`);
console.log(` 更新时间: ${s.last_updated || '无'}`);
if (s.total > 0) {
console.log(' 任务类型分布:');
for (const [type, count] of Object.entries(s.by_type)) {
if (count > 0) console.log(` ${type}: ${count}`);
}
}
break;
}
case 'run': {
const task = dequeue();
if (task) {
console.log(`🚀 取出任务: ${task.task_id}`);
} else {
console.log('✅ 队列为空,无待执行任务');
}
break;
}
case 'cleanup': {
cleanup();
break;
}
default:
console.log('用法: node core/task-queue [status|run|cleanup]');
}
}
module.exports = { loadQueue, enqueue, enqueueBatch, dequeue, complete, fail, status, cleanup };