5.4 KiB
5.4 KiB
主线程解耦审计(2026-09-27,只读审计结论 → W4-D 修复清单)
结论
生产容器 API 与 worker 分进程;RSS/快照/刮削/入库主链路走任务引擎 + outbox。漏网三类:
- HTTP 请求内同步重活:
POST /library/reconcile(全量 stat)、POST /download-cache/cleanup(删种删数据)、POST /organization(planImport 递归 walk)、POST /capabilities/{id}/invoke中 release.search/release.inspect/identity.resolve/catalog.lookup(远程站点/TMDB)、GET /inventory/media-servers(串行 Emby)。 - acquisition-organize 后台循环(index.ts)绕过引擎直接调
submitDownload、executeRecord(Copy/Move)、cleanupDownloadCache、reconcileLibrary,串行 await;无租约/attemptToken 保护;一次大复制卡住 qB 同步与阈值暂停。 - worker 并发度固定 4(openworkflow-engine.ts),runAgent 整段会话占 1 槽数分钟,与 verifyAndImport 大文件复制抢同一池。 事件循环丢租约风险低(复制/哈希流式让出;租约 30s/续租 15s);强制 sha256 路径(目标已存在、跨设备恢复)会全量读两遍。
修复清单(W4-D)
- P0 后台循环只编排:sweepPendingImports → enqueue verifyAndImport;sweepReservedPlans → enqueue submitDownload;超阈值清理与 6h 对账 → enqueue(幂等键按时间槽);tick 只剩 syncDownloads + 阈值判断,qB 同步独立定时器。
- P0
/download-cache/cleanup、/library/reconcile改入队返回 {taskId, runId}(enqueueTracked);前端经任务页/SSE 追踪。 - P1
WORKER_CONCURRENCY配置;worker 分组:--role worker(io 组:除 runAgent/resolveDecision 外,并发 4)与worker:agent(并发 1–2),startWorker两次各带 versions;模块 start() 循环只在 io 组;entrypoint 起三进程。 - P1 capabilities invoke 分级:外部 IO 型能力在 HTTP 路径强制
AbortSignal.timeout(15s)+ 按站点/TMDB 限并发,或改入队返回 taskId;POST /organizationdryRun 的 walk 加文件数上限。 - P2 fs/copy.ts:highWaterMark 1MiB;强制 sha256 全量比对改子进程
sha256sum(仿 ffprobe.ts 的 Deno.Command);executeRecord 打点。 - P2 worker 事件循环延迟探针(setInterval 偏差 >5s warn)。
W4-D 修复状态(2026-09-27)
| 项 | 状态 | 说明 |
|---|---|---|
| P0 后台循环只编排 | 已完成(fe9693d) |
acquisition-organize/index.ts 拆成两个自调度定时器:sync(syncDownloads + 阈值暂停/恢复)与 plan(编排)。超阈值 → 入队 cleanupDownloadCache(业务键 threshold:<5min 槽>,上一轮 pending/running 时跳过);sweepReservedPlans → 入队 submitDownload(业务行 plan:<id>,引擎键 …:<5min 槽>,上次 run 仍活跃则跳过);sweepPendingImports → 入队 verifyAndImport(业务行 import:<dtId>,同上);6h 对账 → 入队 reconcileLibrary(auto:<6h 槽>)。顺带修正:补入库巡检改按 completed_at 选(同步每轮刷新 updated_at,原条件永远选不中)。测试 __tests__/background-loop.test.ts:巡检只入队、50MB 入库(复制 + sha256 + 2.5s 慢 ffprobe)进行中 mock qB torrents/info 请求间隔 < 1s |
| P0 cleanup / reconcile 端点入队 | 已完成(fe9693d) |
POST /download-cache/cleanup、POST /library/reconcile 改 enqueueTracked 返回 {taskId, runId}(202,幂等键按分钟槽);前端"立即清理"提示任务 id 并跳 /console/engine/<runId> |
| P1 worker 分组 + 并发配置 | 已完成(a9cee69、473c5e9、3792868) | WORKER_CONCURRENCY(4)/WORKER_AGENT_CONCURRENCY(2);--role worker(io 组 + relay + 模块循环)、--role worker:agent(runAgent/resolveDecision)、--role all(两池同进程);@umt/tasks 带 versions 的 worker 在认领 SQL 上按任务名过滤(OpenWorkflow 原生认领不看任务名,误认领会按 5s→5m 退避)。entrypoint 三进程互相看护。测试 packages/tasks/test/worker-groups.test.ts(去掉过滤即失败) |
| P1 capabilities invoke 分级 | 已完成(473c5e9) |
modules/agent/invoke-limits.ts:release.search(实时搜索)/release.inspect(refreshDetail)/identity.resolve/catalog.lookup(includeRemote)在 HTTP 路径 15s 超时(502)+ 站点并发 2 / TMDB 并发 4(排队超时 429);许可在底层调用真正结束后才归还 |
P1 POST /organization-records walk 上限 |
已完成(f9c20c6) |
ORGANIZE_WALK_MAX_FILES(5000);dryRun 超出返回 truncated: true(计划只含前 N 个),正式执行 too_many_files 失败 |
| P2 copy highWaterMark / sha256 子进程 / 打点 | 已完成(f9c20c6) |
读写流 1 MiB;强制全量 sha256(复制后回读、目标已存在比对、跨卷恢复、计划期同尺寸目标)走 Deno.Command("sha256sum"),不可用(未安装 / 无 --allow-run)回退进程内流式,结果记 hashVia,sha256Stats() 计数;executeRecord 每文件打 organize.transfer 日志(耗时/字节/MB/s/hashVia) |
| P2 worker 事件循环延迟探针 | 已完成(473c5e9) |
1s 采样,偏差 > 5s warn + 计数,随心跳事件发 loopLagWarnings/maxLoopLagMs |
| 打包遗留 | 已完成(f6457a2、3792868) | 镜像带静态 ffprobe(mwader/static-ffmpeg:7.1.1),编译 --allow-run=ffprobe,sha256sum;settings.agent.sessionDir(null = DATA_DIR/agent-sessions)进设置页;镜像压缩 107→160.5 MB(ffprobe 层 135 MB 未压缩);umtw4d 临时部署验证 health、三进程、ffprobe/sha256sum 可调用 |
| 未做 | 遗留 | GET /inventory/media-servers 串行 Emby 仍在请求内(审计列出但不在 W4-D 清单);invoke 超时后底层调用继续跑完(handler 不全认 signal) |