feat(server): io/agent worker groups, invoke limits for external IO capabilities, loop lag probe

- WORKER_CONCURRENCY / WORKER_AGENT_CONCURRENCY; --role worker (io), worker:agent, all (both)
- HTTP invoke of release.search/inspect, identity.resolve, catalog.lookup(remote):
  15s timeout + per-upstream semaphore (site 2, TMDB 4)
- worker event-loop lag probe: warn + count when drift > 5s

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-27 22:12:16 +08:00
1 parent fe9693d4ca
commit 473c5e94a5
7 files changed
+399 -19

No files matched your search

+23 -4
View File
@@ -12,11 +12,22 @@ import { diffCounts, enableReadOnlyReconcile, exportMappings, type MappingExport
import { auditStorageWarnings, checkStorage, loadMountedPaths, runPreflight } from "./preflight.ts";
import { startWorker } from "./worker/index.ts";
// api/worker/all 是常驻角色;其余是容器入口 / 备份恢复脚本用的一次性子命令:
// api / worker / worker:agent / all 是常驻角色(worker = io 组:除 runAgent/resolveDecision 外的任务 + outbox 中继 +
// 模块后台循环;worker:agent = 只跑 Agent 会话任务;all = api + 两组 worker 同进程);其余是容器入口 / 备份恢复脚本用的一次性子命令:
// migrate | preflight | probe
// export-mappings --out <file.json> [--compare <基准清单.json>] 映射清单导出(可与基准比行数)
// read-only-on [--reason <文本>] 打开 automation.readOnlyReconcile
const Roles = ["api", "worker", "all", "migrate", "preflight", "probe", "export-mappings", "read-only-on"] as const;
const Roles = [
"api",
"worker",
"worker:agent",
"all",
"migrate",
"preflight",
"probe",
"export-mappings",
"read-only-on",
] as const;
type Role = (typeof Roles)[number];
const OneShot = ["migrate", "preflight", "export-mappings", "read-only-on"] as const;
type OneShotRole = (typeof OneShot)[number];
@@ -195,12 +206,20 @@ if (role === "api" || role === "all") {
await server.finished;
});
}
if (role === "worker" || role === "all") {
if (role === "worker" || role === "worker:agent" || role === "all") {
const worker = await startWorker({
logger,
heartbeatMs: config.WORKER_HEARTBEAT_MS,
bus,
runtime: { ctx, modules: SERVER_MODULES, setRelay: outbox.setRelay },
runtime: {
ctx,
modules: SERVER_MODULES,
setRelay: outbox.setRelay,
group: role === "all" ? "split" : role === "worker" ? "io" : "agent",
taskNames: booted.tasks.names(),
concurrency: config.WORKER_CONCURRENCY,
agentConcurrency: config.WORKER_AGENT_CONCURRENCY,
},
});
stops.push(worker.stop);
}