docs(tasks): T-571 add before_srcs snapshot, bounded recovery wait, NEW_IMAGE_NOT_FOUND note
补两个恢复缺口:UPLOAD_* 失败返回须带上传前 src 快照(识别新图的 唯一可靠判据,否则只能启发式猜、违反不做猜测性二次操作原则); 提前台后的恢复等待须有固定时限(≤180s,防并行模式占死账号线程)。 另加 NEW_IMAGE_NOT_FOUND 可选纳入升级清单的备注(带 new_src、 恢复同 DRAG_NOT_FIRST 路径)。验收要点同步两条断言。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
78870aea90
commit
d595e7455c
+27
-9
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: T-571
|
||||
title: ③更新抢前台降频:每账号只提一次 Chrome 前台 + 拖拽/上传失败自动升级前台重试
|
||||
title: ③更新抢前台降频:每账号只提一次 Chrome 前台 + 拖拽/上传失败安全升级前台恢复
|
||||
phase: 7
|
||||
deps: [T-402, T-562]
|
||||
status: TODO
|
||||
@@ -21,16 +21,26 @@ created: 2026-07-09
|
||||
|
||||
- `apply_task` 增加 `bring_to_front` 参数(默认 `True` 保持函数级向后兼容),透传给 `open_product`。
|
||||
- ③ `ApplyWorker`(`app/gui/workers.py` 更新循环)维护「本轮已提过前台的账号集合」:同一账号**第一条任务** `bring_to_front=True`(换账号提示一次,有「正在处理该店」的信号意义),**该账号后续任务传 `False`**。
|
||||
- worker 重开/新一轮更新 → 集合重置(每轮每账号仍提一次)。
|
||||
- 该集合必须在 `ApplyWorker` 生命周期内维护,跨当前本轮的所有分批生效;worker 重开/新一轮更新才重置。
|
||||
- 因 ③ 支持多账号并行,集合访问必须线程安全,建议 `self._foregrounded_aliases = set()` + `self._foreground_lock = threading.Lock()`,通过 helper 原子判断“本账号是否本轮首次前台”。
|
||||
|
||||
### 方案 2:拖拽/上传失败自动升级前台重试(兜底)
|
||||
### 方案 2:拖拽/上传失败自动升级前台安全恢复(兜底)
|
||||
|
||||
- `apply_task`(或 `replace_cover` 调用层)当封面替换结果 reason ∈ {`DRAG_NOT_FIRST`, `UPLOAD_STILL_PROCESSING`, `UPLOAD_TIMEOUT`} 且本次是后台态(`bring_to_front=False`)时:
|
||||
- `Page.bringToFront` 提前台 → **同一 tab 内重试一次** `replace_cover`;
|
||||
- 重试仍失败 → 按既有失败口径返回,不无限重试;
|
||||
- 升级重试要发 on_step 事件(如 `cover_retry_foreground`),run_logs 可见「已提前台重试」。
|
||||
- `Page.bringToFront` 提前台;
|
||||
- **不得完整重跑 `replace_cover()`**。`replace_cover()` 是破坏性流程,开头会删除当前第一张图;如果第一次已经删除旧封面,第二次完整重跑可能继续删除第二张原图或处理中的新图。
|
||||
- 只能在同一 tab 内做安全恢复:
|
||||
- `UPLOAD_STILL_PROCESSING` / `UPLOAD_TIMEOUT`:提前台后继续等待当前上传队列完成,重新读取 `_image_rects()` / `_upload_state()`,如果发现本次新上传图已取得 `susercontent` 地址,再进入拖到第一位校验;不得重新删除、不得重新选择本地文件。
|
||||
- `DRAG_NOT_FIRST`:使用第一次 `replace_cover()` 返回的 `new_src`,提前台后重新读取当前图片列表,只对已存在的 `new_src` 再拖到第一位并校验;不得重新上传、不得重新删除。
|
||||
- 如果缺少 `new_src` 或无法安全识别当前新图,直接按既有失败口径返回,保留现场,不做猜测性二次操作。
|
||||
- 安全恢复只做一次;仍失败 → 按既有失败口径返回,不无限重试。
|
||||
- 升级恢复要发 `on_step` 事件(如 `cover_retry_foreground`),run_logs 可见「后台上传/拖拽疑似受限,已提前台恢复一次」。
|
||||
- 只对上述三个「疑似后台节流」的 reason 升级;其他失败(`OLD_COVER_BACKUP_MISSING`、`UPLOAD_DUPLICATE_IMAGE`、`UPLOAD_CROP_REQUIRED` 等)与前台与否无关,不升级、不重试。
|
||||
- 升级重试前须重新读取页面图片状态(`_image_rects`/`_upload_state`),不能拿失败前的旧 rects 继续拖。
|
||||
- 可在 `editor.py` 内抽小 helper,复用现有图片状态读取、拖拽和上传完成判断逻辑;但不要改变 `replace_cover()` 对外返回结构,除非仅补充安全恢复所需的非破坏性上下文字段(例如 `new_src`、上传后的 count/状态快照)。
|
||||
- **`UPLOAD_*` 失败返回必须带上传前 src 快照(`before_srcs`)**:恢复时识别「本次新上传的图」的唯一可靠判据是 src 不在上传前集合里(`editor.py:982/1045`)。当前 `UPLOAD_STILL_PROCESSING`/`UPLOAD_TIMEOUT` 返回不含 `before_srcs` 且 `new_src` 为 None——不补此字段,恢复只能启发式猜新图,违反上面「不做猜测性二次操作」的原则。
|
||||
- **恢复等待必须有明确时限**:提前台后的「继续等待上传完成」不得无界,给固定预算(≤ 首跑同款 `timeout=180s`,建议 120s),超时按原口径失败。否则并行模式下一个卡死上传会占住一个账号线程不放。
|
||||
- **可选备注**:`NEW_IMAGE_NOT_FOUND`(`editor.py:1084`,上传已拿到 `new_src` 但随后 rects 中找不到)同样可能是后台重渲染/节流所致,且已带 `new_src`、恢复方式与 `DRAG_NOT_FIRST` 同款(重读 rects + 重拖)。是否纳入升级清单由实现者定;纳入则复用 `DRAG_NOT_FIRST` 的恢复路径与单测口径。
|
||||
|
||||
### 文档同步(必须一起改,防止被当 bug 改回)
|
||||
|
||||
@@ -45,10 +55,17 @@ created: 2026-07-09
|
||||
|
||||
- 同一账号连续 N 条任务:仅第一条调用 `Page.bringToFront`(单测 mock `open_product`/CDP 断言调用次数=账号数,不是任务数)。
|
||||
- 换账号 → 新账号第一条再提一次前台。
|
||||
- 后台态封面替换返回 `DRAG_NOT_FIRST`/`UPLOAD_STILL_PROCESSING`/`UPLOAD_TIMEOUT` → 自动提前台重试一次;重试成功计成功;重试失败按原失败口径。
|
||||
- 分批更新时,同一账号跨多个批次仍只在本轮第一次提一次前台;新一轮 worker 才重置。
|
||||
- 多账号并行时,前台集合判断线程安全;同账号不会因并发/分批重复判为首次。
|
||||
- 后台态封面替换返回 `DRAG_NOT_FIRST`/`UPLOAD_STILL_PROCESSING`/`UPLOAD_TIMEOUT` → 自动提前台安全恢复一次;恢复成功计成功;恢复失败按原失败口径。
|
||||
- 后台安全恢复不得完整调用第二次 `replace_cover()`;不得第二次删除第一张图;不得第二次重新上传同一文件。单测需覆盖该安全边界。
|
||||
- `DRAG_NOT_FIRST` 恢复只允许基于第一次返回的 `new_src` 重拖;`new_src` 缺失或页面找不到该图时失败并保留现场。
|
||||
- `UPLOAD_STILL_PROCESSING` / `UPLOAD_TIMEOUT` 恢复只允许继续等待当前上传结果;无法确认新图时失败并保留现场。
|
||||
- `UPLOAD_*` 失败返回含 `before_srcs`(上传前 src 快照),恢复用它识别新图(单测断言字段存在且被恢复逻辑消费)。
|
||||
- 恢复等待有固定时限(≤180s),超时按原口径失败、不无限等待(单测用 mock 时钟或短时限覆盖)。
|
||||
- 前台态(该账号首任务)失败 → 不重复升级(已在前台,无升级意义),按原口径。
|
||||
- 其他失败 reason(重复图/需裁剪/备份缺失等)→ 不触发升级重试。
|
||||
- 升级重试有 run_logs 事件可见。
|
||||
- 升级恢复有 run_logs 事件可见,文案为中文,不暴露技术栈细节给普通用户。
|
||||
- `apply_task` 默认参数不变,直接调用的旧代码行为不回归。
|
||||
- 既有 ③ 更新链路测试(`tests/test_gui.py`/`tests/test_editor_login.py` 相关)不回归。
|
||||
- 验证命令(unittest,不引入 pytest):
|
||||
@@ -61,7 +78,8 @@ created: 2026-07-09
|
||||
## 边界(不改什么)
|
||||
|
||||
- 不改①采集就绪/前台策略(T-562 保持)、④登录页 `activate_tab` 行为。
|
||||
- 不改 `replace_cover`/`change_title`/`click_update` 的交互逻辑本身(只在外层加升级重试编排)。
|
||||
- 不改 `change_title`/`click_update` 的交互逻辑。
|
||||
- 不把后台失败恢复实现为第二次完整 `replace_cover()`;不做可能二次删除线上图片的自动操作。
|
||||
- 不改 Chrome 启动参数、CDP 选择器、DB schema、AI/cmhub 链路。
|
||||
- 不做⑤设置开关。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user