Files
cmshoppe/docs/tasks/T-571.md
T
chengmaandClaude Opus 4.8 78870aea90 docs(tasks): add T-571 reduce apply foreground stealing (per-account + escalate on failure)
③更新每条任务 Page.bringToFront 抢前台改为:每账号首任务提一次 +
后台态拖拽/上传疑似节流失败(DRAG_NOT_FIRST/UPLOAD_STILL_PROCESSING/
UPLOAD_TIMEOUT)自动升级前台重试一次。含①③不对称技术原因
(Windows 遮挡节流)、文档同步项与不做启动参数的红线说明。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:41:49 +08:00

71 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-571
title: ③更新抢前台降频:每账号只提一次 Chrome 前台 + 拖拽/上传失败自动升级前台重试
phase: 7
deps: [T-402, T-562]
status: TODO
created: 2026-07-09
---
## 问题 / 背景
③更新蝦皮时,`apply_task`(`app/editor.py:1248`)每条任务调 `open_product(account, item_id)`,走默认 `bring_to_front=True`(`editor.py:756`):`create_tab_info(background=False)` 以激活态建 tab + `Page.bringToFront`(`editor.py:777`)把整个 Chrome 窗口提到 OS 前台。**用户切到其他软件后,每开始一条任务(几十秒一条)Chrome 就抢一次前台**,批量几百条 = 焦点被抢几百次,正在输入的内容可能误入 Chrome。
①采集已是 `bring_to_front=False`(T-562,`editor.py:830`)。**①③不对称有技术原因,不能无脑把③改 False**:①只读;③要做真实 UI 交互(`cdp.drag` 34 步拖拽换首图、上传等待、点更新)。CDP `Input.dispatchMouseEvent` 注入渲染进程不需要 OS 焦点,但 Windows 上 Chrome 有遮挡检测(occlusion tracking):窗口被**完全遮挡或最小化** → `visibilityState: hidden` → rAF 暂停、JS timer 节流到 1 次/秒,Shopee 拖拽排序库/上传组件可能失灵(`DRAG_NOT_FIRST`、`UPLOAD_STILL_PROCESSING` 假超时)。部分可见则正常。
结论:「不抢前台」与「交互必成」在完全遮挡时真冲突 → 用「每账号一次 + 失败升级」组合化解。
## 方案(改哪个文件、改成什么)
### 方案 1:抢前台从「每任务」降为「每账号一次」
- `apply_task` 增加 `bring_to_front` 参数(默认 `True` 保持函数级向后兼容),透传给 `open_product`。
- ③ `ApplyWorker`(`app/gui/workers.py` 更新循环)维护「本轮已提过前台的账号集合」:同一账号**第一条任务** `bring_to_front=True`(换账号提示一次,有「正在处理该店」的信号意义),**该账号后续任务传 `False`**。
- worker 重开/新一轮更新 → 集合重置(每轮每账号仍提一次)。
### 方案 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 可见「已提前台重试」。
- 只对上述三个「疑似后台节流」的 reason 升级;其他失败(`OLD_COVER_BACKUP_MISSING`、`UPLOAD_DUPLICATE_IMAGE`、`UPLOAD_CROP_REQUIRED` 等)与前台与否无关,不升级、不重试。
- 升级重试前须重新读取页面图片状态(`_image_rects`/`_upload_state`),不能拿失败前的旧 rects 继续拖。
### 文档同步(必须一起改,防止被当 bug 改回)
- `docs/04-architecture.md` / `docs/routes.md` 里「③更新打开商品页保持前台」的表述更新为「每账号首任务提一次前台 + 失败升级」;注明 ①(T-562 完全不抢)与 ③(低频抢 + 升级)的不对称是有意设计及技术原因(遮挡节流)。
### 不做(本任务边界内明确排除)
- 不加 `--disable-backgrounding-occluded-windows` 等 Chrome 启动参数(典型自动化指纹,触碰「不绕过 Shopee 风控」红线的灰区,收益不值)。
- ⑤设置开关「更新时保持 Chrome 前台」本期不做,若后续有用户环境后台老失败再提任务。
## 验收要点
- 同一账号连续 N 条任务:仅第一条调用 `Page.bringToFront`(单测 mock `open_product`/CDP 断言调用次数=账号数,不是任务数)。
- 换账号 → 新账号第一条再提一次前台。
- 后台态封面替换返回 `DRAG_NOT_FIRST`/`UPLOAD_STILL_PROCESSING`/`UPLOAD_TIMEOUT` → 自动提前台重试一次;重试成功计成功;重试失败按原失败口径。
- 前台态(该账号首任务)失败 → 不重复升级(已在前台,无升级意义),按原口径。
- 其他失败 reason(重复图/需裁剪/备份缺失等)→ 不触发升级重试。
- 升级重试有 run_logs 事件可见。
- `apply_task` 默认参数不变,直接调用的旧代码行为不回归。
- 既有 ③ 更新链路测试(`tests/test_gui.py`/`tests/test_editor_login.py` 相关)不回归。
- 验证命令(unittest,不引入 pytest):
- `py -3.10 -m unittest tests.test_gui tests.test_editor_login`
- `python -m ruff check app tests main.py`
- `py -3.10 -m compileall app main.py`
- `py -3.10 -m unittest discover -s tests`
- `git diff --check`
## 边界(不改什么)
- 不改①采集就绪/前台策略(T-562 保持)、④登录页 `activate_tab` 行为。
- 不改 `replace_cover`/`change_title`/`click_update` 的交互逻辑本身(只在外层加升级重试编排)。
- 不改 Chrome 启动参数、CDP 选择器、DB schema、AI/cmhub 链路。
- 不做⑤设置开关。
## 执行记录
(做完在这里写:改了什么文件、跑了什么验证命令及结果、遇到的阻塞、关键决策。)