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>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
bd99a0d5b7
commit
78870aea90
@@ -0,0 +1,70 @@
|
||||
---
|
||||
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 链路。
|
||||
- 不做⑤设置开关。
|
||||
|
||||
## 执行记录
|
||||
|
||||
(做完在这里写:改了什么文件、跑了什么验证命令及结果、遇到的阻塞、关键决策。)
|
||||
Reference in New Issue
Block a user