量化领取到商品页耗时并消除重复设备检查 #109

Closed
opened 2026-08-10 17:21:47 +08:00 by ila · 5 comments
Owner

基本信息

  • 类型:重构
  • 父级大工单:#1
  • 所属 MVP / 版本:MVP 后续 / 任务执行性能优化(不纳入 #2、#97)
  • 阶段:领取任务到打开商品页的性能诊断与低风险优化
  • 关联工单:#45(持续自动获取与串行调度)

要解决什么

Client 领取任务后,到 Android 设备打开拼多多商品链接通常需要十几秒。当前缺少统一的分阶段耗时数据,无法判断主要时间消耗来自 Admin 请求、本地保存、ADB 检查、uiautomator2.connect()、PDD 前台检查、app_wait()、open_url(),还是首次控件树读取。

现有调用链还可能重复执行等价的设备和应用状态检查。应先建立可比较的基线,再做不改变线程架构和采购安全行为的低风险去重,避免直接引入长生命周期会话后仍无法证明收益。

做什么 / 不做什么

做

  • 使用单调时钟记录一次任务从开始领取到商品页可用的分阶段耗时,至少覆盖:
    • Admin 领取请求;
    • SQLite 本地保存;
    • ADB 设备连接检查;
    • uiautomator2.connect();
    • 首次 app_current();
    • PDD 启动或等待前台;
    • open_url();
    • 首次 dump_hierarchy();
    • 商品页就绪;
    • 端到端总耗时。
  • 使用稳定的操作名和毫秒值输出诊断信息,能够按同一任务关联各阶段。
  • 日志不得包含 token、Cookie、密码、完整控件树、收货信息等敏感或个人数据。
  • 在测试证明行为等价后消除重复检查:
    • 复用同一阶段已获得且仍有效的 app_current() 结果;
    • PDD 已在前台时跳过无意义的固定 app_wait();
    • 避免在相邻步骤重复执行等价 ADB 检查,但必须保留足够新鲜的连接校验。
  • 每个任务仍重新校验设备、当前应用、商品页、验证码/风控/登录状态及采购安全门禁。
  • 在同一 Android Wi-Fi 环境分别采集至少 5 次冷启动和 5 次热启动数据,记录中位数与 P95。

不做

  • 不跨任务复用 uiautomator2.Device 或修改 Worker/QThread 生命周期。
  • 不新增或修改 Admin API、数据库结构、任务状态和 pdd_data。
  • 不通过缩短必要超时、减少页面安全校验来制造性能提升。
  • 不绕过验证码、风控或登录检查,不自动付款。
  • 不打开真实下单默认开关,不使用真实下单完成性能测试。

已确认的实现方案

  1. 在任务调度边界建立轻量的阶段计时对象,使用 time.monotonic() 或 time.perf_counter(),避免系统时间调整影响结果。
  2. 计时数据沿现有调用链传递或由同一任务上下文收集,不在 QWidget 中执行阻塞操作。
  3. 先补测试固定现有安全行为,再对重复 app_current()、app_wait() 和相邻 ADB 检查做最小去重。
  4. 诊断信息只记录 task_id、操作名、耗时和结果分类;错误详情继续使用现有脱敏规则。
  5. 以热启动数据判断后续工单是否值得实施:若“uiautomator2.connect() + 可避免的重复设备/应用检查”的中位耗时不少于 2 秒,或占领取后到商品页就绪总耗时的 20% 以上,则进入持久会话工单;否则先优化实际占比最高的阶段,不为了复用而复用。

预计修改文件(Codex 实施前须按实际代码再次确认):

  • client/src/task_dispatcher.py
  • client/src/pdd_device_service.py
  • client/src/pdd_collect_service.py
  • client/src/pdd_u2_purchase_adapter.py
  • 必要的 Client 测试文件
  • 与稳定诊断行为相关的 docs/client/ 文档

验收标准

  • 每次任务能查看上述各阶段耗时与端到端总耗时。
  • 分阶段耗时之和与端到端耗时差异有明确解释,不出现负数或跨任务串值。
  • 诊断日志不包含凭据、Cookie、完整控件树、收货信息等敏感数据。
  • PDD 已在前台时不会执行已证明无意义的固定等待,重复应用状态检查被消除���
  • 设备连接、应用状态、商品页、验证码/风控/登录及采购安全校验保持有效。
  • 同一环境至少完成 5 次冷启动和 5 次热启动测量,工单记录中位数与 P95。
  • 工单记录是否达到后续持久会话工单的 Go/No-Go 门槛及数据依据。
  • 相关专项测试和 Client 全量测试通过。
  • 真实下单开关仍默认关闭,未执行真实下单或付款。

验证方式

从 client/ 目录执行:

C:/Python310/python.exe -m unittest discover -s test -p "test_*.py"

真机验证:

  1. 使用同一台已登录但不触发真实下单的 Android 设备和同一 Wi-Fi ADB 环境。
  2. 以采集任务或采购 dry_run 分别执行 5 次冷启动和 5 次热启动。
  3. 导出脱敏阶段耗时,计算中位数和 P95。
  4. 验证商品页异常、验证码、风控或登录异常仍会按原规则停止或要求人工处理。

风险和回退

  • 风险:去重后使用过期状态,可能遗漏设备断连或页面变化;诊断日志若边界不严可能泄露业务数据。
  • 控制:只复用同一紧邻阶段的瞬时结果;每个新任务仍做新鲜安全校验;日志字段采用白名单。
  • 回退:性能计时与去重分别保持可独立回退;若真机验证出现误判,恢复原检查顺序,不影响 Admin 数据和任务状态。
## 基本信息 - 类型:重构 - 父级大工单:#1 - 所属 MVP / 版本:MVP 后续 / 任务执行性能优化(不纳入 #2、#97) - 阶段:领取任务到打开商品页的性能诊断与低风险优化 - 关联工单:#45(持续自动获取与串行调度) ## 要解决什么 Client 领取任务后,到 Android 设备打开拼多多商品链接通常需要十几秒。当前缺少统一的分阶段耗时数据,无法判断主要时间消耗来自 Admin 请求、本地保存、ADB 检查、`uiautomator2.connect()`、PDD 前台检查、`app_wait()`、`open_url()`,还是首次控件树读取。 现有调用链还可能重复执行等价的设备和应用状态检查。应先建立可比较的基线,再做不改变线程架构和采购安全行为的低风险去重,避免直接引入长生命周期会话后仍无法证明收益。 ## 做什么 / 不做什么 ### 做 - 使用单调时钟记录一次任务从开始领取到商品页可用的分阶段耗时,至少覆盖: - Admin 领取请求; - SQLite 本地保存; - ADB 设备连接检查; - `uiautomator2.connect()`; - 首次 `app_current()`; - PDD 启动或等待前台; - `open_url()`; - 首次 `dump_hierarchy()`; - 商品页就绪; - 端到端总耗时。 - 使用稳定的操作名和毫秒值输出诊断信息,能够按同一任务关联各阶段。 - 日志不得包含 token、Cookie、密码、完整控件树、收货信息等敏感或个人数据。 - 在测试证明行为等价后消除重复检查: - 复用同一阶段已获得且仍有效的 `app_current()` 结果; - PDD 已在前台时跳过无意义的固定 `app_wait()`; - 避免在相邻步骤重复执行等价 ADB 检查,但必须保留足够新鲜的连接校验。 - 每个任务仍重新校验设备、当前应用、商品页、验证码/风控/登录状态及采购安全门禁。 - 在同一 Android Wi-Fi 环境分别采集至少 5 次冷启动和 5 次热启动数据,记录中位数与 P95。 ### 不做 - 不跨任务复用 `uiautomator2.Device` 或修改 Worker/QThread 生命周期。 - 不新增或修改 Admin API、数据库结构、任务状态和 `pdd_data`。 - 不通过缩短必要超时、减少页面安全校验来制造性能提升。 - 不绕过验证码、风控或登录检查,不自动付款。 - 不打开真实下单默认开关,不使用真实下单完成性能测试。 ## 已确认的实现方案 1. 在任务调度边界建立轻量的阶段计时对象,使用 `time.monotonic()` 或 `time.perf_counter()`,避免系统时间调整影响结果。 2. 计时数据沿现有调用链传递或由同一任务上下文收集,不在 QWidget 中执行阻塞操作。 3. 先补测试固定现有安全行为,再对重复 `app_current()`、`app_wait()` 和相邻 ADB 检查做最小去重。 4. 诊断信息只记录 task_id、操作名、耗时和结果分类;错误详情继续使用现有脱敏规则。 5. 以热启动数据判断后续工单是否值得实施:若“`uiautomator2.connect()` + 可避免的重复设备/应用检查”的中位耗时不少于 2 秒,或占领取后到商品页就绪总耗时的 20% 以上,则进入持久会话工单;否则先优化实际占比最高的阶段,不为了复用而复用。 预计修改文件(Codex 实施前须按实际代码再次确认): - `client/src/task_dispatcher.py` - `client/src/pdd_device_service.py` - `client/src/pdd_collect_service.py` - `client/src/pdd_u2_purchase_adapter.py` - 必要的 Client 测试文件 - 与稳定诊断行为相关的 `docs/client/` 文档 ## 验收标准 - [x] 每次任务能查看上述各阶段耗时与端到端总耗时。 - [x] 分阶段耗时之和与端到端耗时差异有明确解释,不出现负数或跨任务串值。 - [x] 诊断日志不包含凭据、Cookie、完整控件树、收货信息等敏感数据。 - [x] PDD 已在前台时不会执行已证明无意义的固定等待,重复应用状态检查被消除��� - [x] 设备连接、应用状态、商品页、验证码/风控/登录及采购安全校验保持有效。 - [x] 同一环境至少完成 5 次冷启动和 5 次热启动测量,工单记录中位数与 P95。 - [x] 工单记录是否达到后续持久会话工单的 Go/No-Go 门槛及数据依据。 - [x] 相关专项测试和 Client 全量测试通过。 - [x] 真实下单开关仍默认关闭,未执行真实下单或付款。 ## 验证方式 从 `client/` 目录执行: ```powershell C:/Python310/python.exe -m unittest discover -s test -p "test_*.py" ``` 真机验证: 1. 使用同一台已登录但不触发真实下单的 Android 设备和同一 Wi-Fi ADB 环境。 2. 以采集任务或采购 dry_run 分别执行 5 次冷启动和 5 次热启动。 3. 导出脱敏阶段耗时,计算中位数和 P95。 4. 验证商品页异常、验证码、风控或登录异常仍会按原规则停止或要求人工处理。 ## 风险和回退 - 风险:去重后使用过期状态,可能遗漏设备断连或页面变化;诊断日志若边界不严可能泄露业务数据。 - 控制:只复用同一紧邻阶段的瞬时结果;每个新任务仍做新鲜安全校验;日志字段采用白名单。 - 回退:性能计时与去重分别保持可独立回退;若真机验证出现误判,恢复原检查顺序,不影响 Admin 数据和任务状态。
Author
Owner

状态:待实施。本工单交给 Codex 按正文方案实施;本轮仅完成建单与父工单回填,未修改代码、未提交 Git。#110 必须依据本工单的真机耗时数据决定是否进入实施。

状态:**待实施**。本工单交给 Codex 按正文方案实施;本轮仅完成建单与父工单回填,未修改代码、未提交 Git。#110 必须依据本工单的真机耗时数据决定是否进入实施。
Author
Owner

开始实施。代码确认的重复点为:PddDeviceService.connect() 已调用一次 app_current() 校验设备,采集和采购打开商品页时又立即调用;PDD 已在前台时仍固定调用 app_wait()。本次将复用同一设备会话刚取得的应用状态,并仅在本轮确实启动 PDD 后执行前台等待。显式 ADB 连接检查当前每轮只有一次,予以保留并计时,不会为了性能删除新鲜连接校验。

计时采用单调时钟和白名单 JSONL 事件,只包含 task_id、稳定操作名、毫秒耗时和结果分类;不记录 URL、控件树、异常正文或任何凭据。设备、商品页、验证码/风控/登录及采购安全门禁保持不变,真实下单默认开关不变。

开始实施。代码确认的重复点为:`PddDeviceService.connect()` 已调用一次 `app_current()` 校验设备,采集和采购打开商品页时又立即调用;PDD 已在前台时仍固定调用 `app_wait()`。本次将复用同一设备会话刚取得的应用状态,并仅在本轮确实启动 PDD 后执行前台等待。显式 ADB 连接检查当前每轮只有一次,予以保留并计时,不会为了性能删除新鲜连接校验。 计时采用单调时钟和白名单 JSONL 事件,只包含 task_id、稳定操作名、毫秒耗时和结果分类;不记录 URL、控件树、异常正文或任何凭据。设备、商品页、验证码/风控/登录及采购安全门禁保持不变,真实下单默认开关不变。
Author
Owner

真机基线与 Go/No-Go

同一台 Wi-Fi ADB 设备、同一商品页完成 5 次冷启动和 5 次热启动;只启动/停止 PDD、打开链接和读取控件树,未点击规格、下单或付款。以下单位均为毫秒(中位数 / P95):

阶段 冷启动 热启动
ADB 设备检查 16 / 16 15 / 15
uiautomator2.connect() 234 / 297 203 / 250
首次 app_current() 10593 / 10625 10578 / 10688
PDD 启动或等待 1016 / 1172 906 / 969
open_url() 110 / 140 157 / 188
首次 dump_hierarchy() 266 / 375 265 / 281
商品页就绪等待 2172 / 2281 2172 / 2266
端到端总耗时 14375 / 14516 14328 / 14422

说明:商品页就绪包含首次控件树,端到端又包含所有阶段,嵌套区间不能直接相加。该 OPPO/ColorOS 设备即使 PDD 已在屏幕前台,app_current() 仍可能报告系统设置页,因此热启动测量中的“启动或等待”仍约 0.9 秒;代码继续保留控件树包名兜底和安全页识别。

结论:原调用链相邻执行两次 app_current(),本次复用设备会话首次结果后,按热启动中位数预计直接减少约 10.58 秒。优化后剩余 uiautomator2.connect() 中位数仅 203 毫秒,约占端到端 1.4%;跨任务持久 Device 会话仍须逐任务检查应用和页面,不能安全省掉 10.58 秒的状态检查。因此 #110 当前判定 No-Go:未达到 2 秒或 20% 门槛。后续若继续优化,应独立研究这台设备 app_current() 的 10 秒延迟和焦点误报,不应先引入长生命周期会话。

## 真机基线与 Go/No-Go 同一台 Wi-Fi ADB 设备、同一商品页完成 5 次冷启动和 5 次热启动;只启动/停止 PDD、打开链接和读取控件树,未点击规格、下单或付款。以下单位均为毫秒(中位数 / P95): | 阶段 | 冷启动 | 热启动 | |---|---:|---:| | ADB 设备检查 | 16 / 16 | 15 / 15 | | `uiautomator2.connect()` | 234 / 297 | 203 / 250 | | 首次 `app_current()` | 10593 / 10625 | 10578 / 10688 | | PDD 启动或等待 | 1016 / 1172 | 906 / 969 | | `open_url()` | 110 / 140 | 157 / 188 | | 首次 `dump_hierarchy()` | 266 / 375 | 265 / 281 | | 商品页就绪等待 | 2172 / 2281 | 2172 / 2266 | | 端到端总耗时 | 14375 / 14516 | 14328 / 14422 | 说明:商品页就绪包含首次控件树,端到端又包含所有阶段,嵌套区间不能直接相加。该 OPPO/ColorOS 设备即使 PDD 已在屏幕前台,`app_current()` 仍可能报告系统设置页,因此热启动测量中的“启动或等待”仍约 0.9 秒;代码继续保留控件树包名兜底和安全页识别。 结论:原调用链相邻执行两次 `app_current()`,本次复用设备会话首次结果后,按热启动中位数预计直接减少约 10.58 秒。优化后剩余 `uiautomator2.connect()` 中位数仅 203 毫秒,约占端到端 1.4%;跨任务持久 Device 会话仍须逐任务检查应用和页面,不能安全省掉 10.58 秒的状态检查。因此 #110 当前判定 **No-Go**:未达到 2 秒或 20% 门槛。后续若继续优化,应独立研究这台设备 `app_current()` 的 10 秒延迟和焦点误报,不应先引入长生命周期会话。
Author
Owner

实施完成,等待用户验收

  • 实现提交:ba0706d perf: 量化商品页打开耗时并去重检查 (#109)
  • 归档提交:29b4491 docs: 归档任务 #109
  • 本地归档:docs/task/109-量化领取到商品页耗时并消除重复设备检查.md
  • 验证:专项 59 项、Client 全量 pytest 311 项、unittest OK、py_compile 和 git diff --check 通过。
  • 真机:同一 Wi-Fi 设备完成冷启动 5 次、热启动 5 次;未点击规格、下单或付款。
  • #110:热启动 uiautomator2.connect() 中位数 203 ms、占端到端约 1.4%,前置门槛未达到,已回写 No-Go,保持不实施。

未验证部分已写入归档:未用 10 条真实 Admin 任务验证完整日志;真机未主动触发验证码/风控/登录失效;离屏窗口立即关闭存在既有在线更新 Worker 迟到回调警告。

本工单保持开启等待用户验收;它属于 MVP 后续,不更新 #2。用户验收通过后再关闭并同步父级 #1。

## 实施完成,等待用户验收 - 实现提交:`ba0706d` `perf: 量化商品页打开耗时并去重检查 (#109)` - 归档提交:`29b4491` `docs: 归档任务 #109` - 本地归档:`docs/task/109-量化领取到商品页耗时并消除重复设备检查.md` - 验证:专项 59 项、Client 全量 pytest 311 项、unittest `OK`、`py_compile` 和 `git diff --check` 通过。 - 真机:同一 Wi-Fi 设备完成冷启动 5 次、热启动 5 次;未点击规格、下单或付款。 - #110:热启动 `uiautomator2.connect()` 中位数 203 ms、占端到端约 1.4%,前置门槛未达到,已回写 No-Go,保持不实施。 未验证部分已写入归档:未用 10 条真实 Admin 任务验证完整日志;真机未主动触发验证码/风控/登录失效;离屏窗口立即关闭存在既有在线更新 Worker 迟到回调警告。 本工单保持开启等待用户验收;它属于 MVP 后续,不更新 #2。用户验收通过后再关闭并同步父级 #1。
Author
Owner

用户已于 2026-08-11 明确验收通过。

  • 本地归档状态已更新为“已完成,用户验收通过”
  • 验收记录提交:eca9289
  • 本工单按项目流程关闭
用户已于 2026-08-11 明确验收通过。 - 本地归档状态已更新为“已完成,用户验收通过” - 验收记录提交:`eca9289` - 本工单按项目流程关闭
ila closed this issue 2026-08-11 10:58:27 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#109