feat(worker): IO Worker 分道(WK-1)
io worker 进程内按任务声明的 lane 分文件 / 网络 / 维护三条道,各自并发(缺省 2/4/1)、 各自排队;维护道在文件道或网络道有排队/运行时让路(连续 10 分钟放行一个),调度器内联的 清理/回填/保留期裁剪也走维护道。并发在 设置 → 自动化 → 高级 热生效,env 覆盖;旧 WORKER_CONCURRENCY 映射到网络道。运行状态页按道显示运行中/并发/排队。归属表写进 docs/runbook/dev.md,ci 与注册表逐项核对。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
68f53390f6
commit
da33cad81d
38 files changed
+1240
-105
No files matched your search
@@ -12,6 +12,7 @@ import {
|
||||
} from "../../src/modules/schedules/registry.ts";
|
||||
import { Scheduler } from "../../src/modules/schedules/scheduler.ts";
|
||||
import type { ServerContext } from "../../src/modules/types.ts";
|
||||
import { LaneController, setLaneController } from "../../src/worker/lanes.ts";
|
||||
import { Browser, bearer, createHarness, type Harness, pgAvailable } from "../auth-settings/harness.ts";
|
||||
import { DEV_KEY, json } from "../helpers.ts";
|
||||
|
||||
@@ -94,6 +95,58 @@ describe.skipIf(!hasPg)("定时任务注册表(真实 PG)", () => {
|
||||
await h?.close();
|
||||
});
|
||||
|
||||
it("WK-1:lane=maintenance 的内联任务在文件道 / 网络道有活时让路(保持到期),空闲后执行;立即执行不让路", async () => {
|
||||
let busy = true;
|
||||
const logger = ctx.logger;
|
||||
const lanes = new LaneController({
|
||||
engine: { queueCounts: async (g) => g.map(() => ({ queued: busy ? 1 : 0, running: 0 })) },
|
||||
logger,
|
||||
lanes: { file: ["f"], network: ["n"], maintenance: [] },
|
||||
readSettings: async () => ({ file: 2, network: 4, maintenance: 1 }),
|
||||
busyCacheMs: 0,
|
||||
maxYieldMs: 3_600_000,
|
||||
});
|
||||
await lanes.refresh();
|
||||
setLaneController(ctx, lanes);
|
||||
try {
|
||||
registerScheduledJob(ctx, counting("test.lane_maint", { lane: "maintenance" }));
|
||||
registerScheduledJob(ctx, counting("test.lane_light"));
|
||||
const started = await sched.tick();
|
||||
await sched.idle();
|
||||
expect(started).toContain("test.lane_light");
|
||||
expect(started).not.toContain("test.lane_maint");
|
||||
expect(calls.get("test.lane_maint") ?? 0).toBe(0);
|
||||
expect(lanes.yielding()).toBe(true);
|
||||
|
||||
// 立即执行:不让路
|
||||
await h.db
|
||||
.updateTable("scheduled_job")
|
||||
.set({ run_requested_at: new Date() })
|
||||
.where("id", "=", "test.lane_maint")
|
||||
.execute();
|
||||
expect(await sched.tick()).toContain("test.lane_maint");
|
||||
await sched.idle();
|
||||
expect(calls.get("test.lane_maint")).toBe(1);
|
||||
expect(lanes.active("maintenance")).toBe(0);
|
||||
|
||||
// 到期未跑的:空闲后执行
|
||||
await h.db
|
||||
.updateTable("scheduled_job")
|
||||
.set({ next_run_at: new Date(Date.now() - 1000) })
|
||||
.where("id", "=", "test.lane_maint")
|
||||
.execute();
|
||||
expect(await sched.tick()).not.toContain("test.lane_maint");
|
||||
busy = false;
|
||||
expect(await sched.tick()).toContain("test.lane_maint");
|
||||
await sched.idle();
|
||||
expect(calls.get("test.lane_maint")).toBe(2);
|
||||
} finally {
|
||||
setLaneController(ctx, null);
|
||||
reg.unregister("test.lane_maint");
|
||||
reg.unregister("test.lane_light");
|
||||
}
|
||||
});
|
||||
|
||||
it("登记默认值;用户改过的开关与调度不被再次登记覆盖;reset 恢复默认", async () => {
|
||||
registerScheduledJob(ctx, counting("test.keep"));
|
||||
await sched.tick();
|
||||
|
||||
Reference in new issue
Block a user