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:
rootandClaude Opus 5.5 committed 2026-09-27 22:12:16 +08:00
1 parent a9cee69bd2
commit fe9693d4ca
13 files changed
+334 -68

No files matched your search

+2 -2
View File
@@ -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 }),
});
}