feat(downloads): 下载器单独的水位与保种天数

- contracts DownloaderPolicy(存 downloader_instance.settings.policy):硬阈值 / 恢复水位 / 清理目标 / 保种天数,
  不填用全局 cache / retention
- volumeThresholds:卷的生效水位 = 各实例「自己的值 ?? 全局」取最小;decideVolume、阈值清理、手动恢复、
  首页卷信息、定时清理检查都改用它;cleanupCandidates 保种天数按实例
- 保存时校验合并全局后 恢复 < 硬阈值、清理目标 ≤ 恢复
- 下载器设置表单新增四项(留空用全局)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 20:51:04 +08:00
1 parent ff79554a09
commit ee128e0b3f
9 files changed
+158 -14

No files matched your search

@@ -1,5 +1,7 @@
import type { CacheSettings } from "@umt/contracts";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { loadInstances, pickInstance } from "../../src/modules/acquisition-organize/services/common.ts";
import { instancePolicy, volumeThresholds } from "../../src/modules/acquisition-organize/services/volumes.ts";
import { createHarness, type Harness, pgAvailable, seedBase } from "./harness.ts";
const hasPg = await pgAvailable();
@@ -61,3 +63,35 @@ describe.skipIf(!hasPg)("下载器选择", () => {
).rejects.toThrow();
});
});
describe("下载器自己的水位 / 保种", () => {
const cache = { hardThresholdPercent: 85, resumePercent: 75, cleanupTargetPercent: 70 } as CacheSettings;
const inst = (policy?: unknown) => ({ inst: { settings: policy === undefined ? {} : { policy } } }) as never;
it("没设用全局;单实例用自己的值(可以比全局宽松)", () => {
expect(volumeThresholds({ instances: [inst()] }, cache)).toEqual({
hardThresholdPercent: 85,
resumePercent: 75,
cleanupTargetPercent: 70,
});
expect(volumeThresholds({ instances: [inst({ hardThresholdPercent: 95, resumePercent: 90 })] }, cache)).toEqual({
hardThresholdPercent: 95,
resumePercent: 90,
cleanupTargetPercent: 70,
});
});
it("多实例共用一块盘:各自生效值里取最严格", () => {
const th = volumeThresholds(
{ instances: [inst({ hardThresholdPercent: 95 }), inst({ resumePercent: 60 })] },
cache,
);
expect(th).toEqual({ hardThresholdPercent: 85, resumePercent: 60, cleanupTargetPercent: 70 });
});
it("保种天数按实例取;格式不对当没设", () => {
expect(instancePolicy({ settings: { policy: { seedRetentionDays: 0 } } })).toEqual({ seedRetentionDays: 0 });
expect(instancePolicy({ settings: { policy: { seedRetentionDays: -1 } } })).toEqual({});
expect(instancePolicy({ settings: null })).toEqual({});
});
});