09-01 调度机制修复落地+并发方案A+全链路复测通过
- 调度根因修复:工作台/api/run 显式写 next_run_at=now+5s(17列),scheduledAt=now+5s 带秒 - 新增 自动化任务调度机制.md(根因/硬规则/状态机/并发上限≈3/排查命令) - 并发方案A(浏览器锁):/api/run 对浏览器类任务自动注入锁约束;浏览器搜索抖音账号操作规范.md 新增5.6并发互斥 - 端口 8899→8900 可传参(8899被小米MiPCAudio.exe系统服务占用且杀后复活) - cdp-test-junxi.mjs 支持 --port 参数 - SKILL.md 工作台段落同步修正(旧认知 scheduled_at=now 已废弃) - 俊希全流程 TC-01~11 复测全通过(验收表更新):并行解析6条+AI写脚本会话链路完整跑通
This commit is contained in:
1 parent
ccdd79ea40
commit
24886338d1
12 files changed
+265
-49
No files matched your search
@@ -1,5 +1,5 @@
|
||||
// MCN工作台 - 本地 Web 服务(零依赖 Node 实现)
|
||||
// 启动: node server.js → http://localhost:8899
|
||||
// 启动: node server.js [端口] → http://localhost:8899(默认;可传参指定端口,如 node server.js 8900)
|
||||
// 功能: 技能导航 + 产出内容浏览(默认读桌面 MCNSkill项目)+ dsh 数据功能页(账号/视频/脚本/复盘/周榜,只读)
|
||||
'use strict';
|
||||
|
||||
@@ -10,7 +10,9 @@ const os = require('os');
|
||||
const { URL } = require('url');
|
||||
const dsh = require('./dsh-data');
|
||||
|
||||
const PORT_BASE = 8899;
|
||||
// 09-01 端口改为可传参(默认8899):本机 8899 可能被小米 PC 管家 MiPCAudio.exe 系统服务占用(0.0.0.0 监听且自动复活),
|
||||
// 此时 127.0.0.1:8899 绑定不生效 → 用 `node server.js 8900` 显式换端口
|
||||
const PORT_BASE = parseInt(process.argv[2], 10) || 8899;
|
||||
const ROOT = __dirname;
|
||||
const PUBLIC_DIR = path.join(ROOT, 'public');
|
||||
const CONFIG_FILE = path.join(ROOT, 'config.json');
|
||||
@@ -361,19 +363,35 @@ const server = http.createServer((req, res) => {
|
||||
try {
|
||||
const { prompt, name } = JSON.parse(body || '{}');
|
||||
if (!prompt || typeof prompt !== 'string' || !prompt.trim()) return sendErr(400, 'prompt 不能为空');
|
||||
// 09-01 并发方案A:浏览器类任务(账号信息/视频列表/采集/导入)自动注入浏览器锁约束——
|
||||
// 多个 AI 会话任务并行共享同一 9223 Chrome 实例,必须互斥使用,否则标签页互相导航抢占
|
||||
const BROWSER_HINT = /账号信息|视频列表|保存并分析|采集|导入账号|网页采集|浏览器/;
|
||||
const BROWSER_LOCK = 'D:\\\\AgentSkill\\\\mcn-workshop\\\\.browser-lock';
|
||||
let finalPrompt = prompt.trim();
|
||||
if (BROWSER_HINT.test(finalPrompt)) {
|
||||
finalPrompt += `
|
||||
|
||||
【浏览器锁约束(必须遵守)】本任务需要操作浏览器(browser-harness / 9223 Chrome)。多个 AI 会话任务可能并行,浏览器是共享单实例,必须互斥使用:
|
||||
1. 执行任何浏览器操作前,先检查锁文件:${BROWSER_LOCK} 是否存在(bash: ls)
|
||||
2. 锁存在 → 等待 10 秒后重试,最多重试 18 次(约 3 分钟);若锁文件修改时间已超过 10 分钟视为死锁,可删除后抢占
|
||||
3. 拿到锁(bash: echo <任务名+时间戳> > ${BROWSER_LOCK})→ 才可操作浏览器
|
||||
4. 浏览器操作全部完成后(无论成功失败)必须删除锁文件(bash: rm -f ${BROWSER_LOCK})
|
||||
5. 若确认本任务实际不需要浏览器(如数据已齐),忽略本条约束,直接跳过`;
|
||||
}
|
||||
const { DatabaseSync } = require('node:sqlite');
|
||||
const db = new DatabaseSync(process.env.WORKBUDDY_DB || path.join(os.homedir(), '.workbuddy', 'workbuddy.db'));
|
||||
const now = Date.now();
|
||||
const id = 'automation-' + now;
|
||||
const cwd = 'D:\\AgentSkill\\mcn-workshop'; // 工作台触发的会话归入 mcn-workshop 空间分组
|
||||
const d = new Date();
|
||||
const d = new Date(Date.now() + 5 * 1000); // 未来 5 秒(08-31 根因:客户端只对未来 scheduledAt 补算 next_run_at;写 now=过去时间→不补算→调度器扫不到→卡死)
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const scheduledAt = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
const scheduledAt = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
||||
const nextRunAt = Date.now() + 5 * 1000; // 08-31 实测:客户端调度器按 next_run_at 扫描;缺此列=null=永不拾取(工作台任务卡死根因)
|
||||
const uidRow = db.prepare("SELECT user_id FROM sessions WHERE user_id IS NOT NULL AND user_id <> '' ORDER BY created_at DESC LIMIT 1").get();
|
||||
const ownerUserId = uidRow ? uidRow.user_id : '';
|
||||
db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
|
||||
.run(id, name || '工作台任务', prompt.trim(), 'ACTIVE', 'once', scheduledAt, '', JSON.stringify([cwd]), now, now, '[]', '[]', 'deepseek-v4-flash', 'fullAccess', ownerUserId, 'confirmed');
|
||||
db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,next_run_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
|
||||
.run(id, name || '工作台任务', finalPrompt, 'ACTIVE', 'once', scheduledAt, nextRunAt, '', JSON.stringify([cwd]), now, now, '[]', '[]', 'deepseek-v4-flash', 'fullAccess', ownerUserId, 'confirmed');
|
||||
db.close();
|
||||
log('已提交 AI 任务: ' + id + (name ? ' (' + name + ')' : ''));
|
||||
return sendJSON(200, { ok: true, id, message: '任务已提交,请在左侧会话栏查看执行' });
|
||||
|
||||
Reference in new issue
Block a user