fix(download): 卡住 / 异常恢复后自动关闭事项(L2),补下载卡死修复测试
stalled → 恢复下载 / 完成、failed / missing → 恢复正常时,关闭同一任务 open / awaiting_user 的 download_stalled / download_failed 事项(resolved,system:download-sync);Agent 调查中的由其自行核实关闭。 新增 download-sync-recovery 测试覆盖 removed 行复活、同 hash 第二个计划、imported 回退、多轮缺席、事项自动关闭。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
d96f0ff19f
commit
1c2fff694b
2 files changed
+361
No files matched your search
@@ -918,6 +918,12 @@ async function observeLocked(
|
||||
merged.status === "paused" ? merged.pauseReason : null,
|
||||
row.generation,
|
||||
);
|
||||
// 卡住 / 异常后恢复正常(进度增长或状态恢复):关闭同一任务未关闭的无进展 / 异常事项
|
||||
if (changed && RECOVERED.has(merged.status)) {
|
||||
if (row.status === "stalled") await closeRecoveredDecision(d, trx, `download_stalled:${row.id}`, merged.status);
|
||||
if (row.status === "failed" || row.status === "missing")
|
||||
await closeRecoveredDecision(d, trx, `download_failed:${row.id}`, merged.status);
|
||||
}
|
||||
if (becameComplete) {
|
||||
stats.completed.push(row.id);
|
||||
const plan = row.acquisition_plan_id
|
||||
@@ -961,6 +967,37 @@ async function observeLocked(
|
||||
return changed;
|
||||
}
|
||||
|
||||
/** 视为"恢复正常"的状态(用户暂停不算恢复,事项留给人看) */
|
||||
const RECOVERED = new Set<DownloadStatus>(["queued", "downloading", "completed", "importing", "imported"]);
|
||||
|
||||
/**
|
||||
* 卡住 / 异常事项自动关闭:只关 open / awaiting_user;Agent 正在调查(investigating)的由它自己核实后关闭。
|
||||
* resolution 不带处理选项,executeResolution 不会再执行任何动作。
|
||||
*/
|
||||
async function closeRecoveredDecision(d: AoDeps, trx: Exec, dedupeKey: string, status: DownloadStatus) {
|
||||
const by = "system:download-sync";
|
||||
const rows = await trx
|
||||
.updateTable("decision")
|
||||
.set({
|
||||
status: "resolved",
|
||||
resolved_by: by,
|
||||
resolved_at: d.ports.now(),
|
||||
resolution: jsonb({ key: "download_recovered", optionKey: null, by, note: `下载已恢复(${status})` }),
|
||||
})
|
||||
.where("dedupe_key", "=", dedupeKey)
|
||||
.where("status", "in", ["open", "awaiting_user"])
|
||||
.returning("id")
|
||||
.execute();
|
||||
for (const r of rows) {
|
||||
await d.ctx.outbox.emit(
|
||||
trx,
|
||||
"decision.updated",
|
||||
{ decisionId: r.id, status: "resolved" },
|
||||
{ idempotencyKey: `decision.updated:${r.id}:resolved` },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** 用户给已有任务贴了管理标签:登记接管,不改保存路径与其它标签 */
|
||||
async function adopt(d: AoDeps, topo: InstanceTopology, t: QbTorrent, now: Date, stats: SyncStats) {
|
||||
const db = d.ctx.db;
|
||||
|
||||
Reference in new issue
Block a user