refactor(ao): background loops only orchestrate; cleanup/reconcile endpoints enqueue
- separate qB sync timer from the planning timer
- threshold cleanup, reserved-plan and pending-import sweeps, 6h reconcile enqueue
engine tasks with time-slot idempotency keys instead of running inline
- pending-import sweep selects by completed_at (sync refreshes updated_at every round)
- POST /download-cache/cleanup and /library/reconcile return {taskId, runId} (202);
web jumps to the engine run page
- test: a 50MB verifyAndImport in progress does not delay qB sync
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
a9cee69bd2
commit
fe9693d4ca
13 files changed
+334
-68
No files matched your search
@@ -102,14 +102,14 @@ export function useCacheVolumes() {
|
||||
});
|
||||
}
|
||||
|
||||
/** 手动清理:只清已验证入库且满足保留/H&R 的纳管任务 */
|
||||
/** 手动清理:服务端入队 cleanupDownloadCache(只清已验证入库且满足保留/H&R 的纳管任务),返回任务 id */
|
||||
export function useCacheCleanup() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (downloaderInstanceId?: string) =>
|
||||
apiMutate("/api/v1/download-cache/cleanup", {
|
||||
body: downloaderInstanceId ? { downloaderInstanceId } : {},
|
||||
}).then((d) => z.object({ report: z.record(z.string(), z.unknown()) }).parse(d)),
|
||||
}).then((d) => z.object({ taskId: z.string(), runId: z.string() }).parse(d)),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: downloadKeys.all }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Dashboard } from "@umt/contracts";
|
||||
import { Brush, HardDrive } from "lucide-react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import { useCacheCleanup, useCacheVolumes } from "~/api/downloads.ts";
|
||||
import { ConfirmDialog } from "~/components/console/confirm-dialog.tsx";
|
||||
@@ -79,6 +80,7 @@ function VolumeBar({ v }: { v: Volume }) {
|
||||
export function CacheVolumes() {
|
||||
const vols = useCacheVolumes();
|
||||
const cleanup = useCacheCleanup();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<section className="pg-slab mb-6 rounded-xl p-4">
|
||||
<div className="mb-3 flex flex-wrap items-center justify-between gap-2">
|
||||
@@ -96,10 +98,8 @@ export function CacheVolumes() {
|
||||
onConfirm={() =>
|
||||
cleanup.mutateAsync(undefined).then(
|
||||
(r) => {
|
||||
const vols = (r.report as { volumes?: { removed?: unknown[]; skipped?: unknown[] }[] }).volumes ?? [];
|
||||
const removed = vols.reduce((n, v) => n + (v.removed?.length ?? 0), 0);
|
||||
const skipped = vols.reduce((n, v) => n + (v.skipped?.length ?? 0), 0);
|
||||
toast.success(`清理完成:移除 ${removed} 个任务的缓存${skipped ? `,${skipped} 个因保留/H&R 跳过` : ""}`);
|
||||
toast.success(`已排队清理任务 ${r.taskId.slice(0, 8)}`, { description: "后台执行,结果见任务详情" });
|
||||
navigate(`/console/engine/${r.runId}`);
|
||||
},
|
||||
(e) => toast.error(errorMessage(e)),
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user