From 40cd8afefddf3ebcf0d4692016f4e3b55921f9cb Mon Sep 17 00:00:00 2001 From: chengma Date: Mon, 10 Aug 2026 18:01:50 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=BD=92=E6=A1=A3=E4=BB=BB=E5=8A=A1=20?= =?UTF-8?q?#110?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10-持久设备工作线程复用uiautomator2会话.md | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 docs/task/110-持久设备工作线程复用uiautomator2会话.md diff --git a/docs/task/110-持久设备工作线程复用uiautomator2会话.md b/docs/task/110-持久设备工作线程复用uiautomator2会话.md new file mode 100644 index 0000000..bfd3cb5 --- /dev/null +++ b/docs/task/110-持久设备工作线程复用uiautomator2会话.md @@ -0,0 +1,99 @@ +# 110 使用持久设备工作线程跨任务复用 uiautomator2 会话 + +- 类型:重构 +- 父级大工单:#1 +- 所属 MVP / 版本:MVP 后续 / 任务执行性能优化 +- 状态:已完成(待验收) +- 日期:2026-08-10 +- Gitea 工单: + +## 背景与目标 + +Client 原来每轮自动获取都会新建 Worker 和 QThread,正式采集、采购和核单适配器 +也会重新调用 `uiautomator2.connect()`。目标是让同一 Android 设备由固定工作线程 +串行控制,并在 90 秒内只复用 Device 连接;页面、控件树、商品、价格、规格和采购 +安全状态仍必须每个任务重新读取。 + +#109 测得连接本身只占端到端约 1.4%,原结论是 No-Go。用户随后明确要求继续实施 +#110,因此工单已记录该决策变更;性能门槛保留为结果评价和回退依据,不再作为 +开始实施的阻塞条件。 + +## 最终方案 + +- `PDDTaskPageEvent` 在首次设备任务时懒创建一个固定 QThread 和长生命周期 + `ClaimTaskWorker`。自动获取、手动重新采集、采购和不可逆阶段后的只读核单都通过 + Qt 队列信号串行进入该 Worker;不在 Worker 内运行无限循环。 +- `PersistentPddDeviceService` 只缓存同一 serial 的 Device 连接。每次 `connect()` + 都重新调用 `app_current()` 做轻量健康检查,并返回全新的任务会话。旧连接失效时 + 丢弃后最多重连一次,不缓存 XML、Selector、坐标或业务字段。 +- 官方采集、dry-run 采购、live 采购和核单工厂从当前执行上下文取得同一个持久设备 + 服务;自定义测试工厂和原有每任务服务边界仍可使用,方便整体回退。 +- 停止自动获取、保存或删除 Android 设备、serial 变化、90 秒空闲到期和窗口关闭时, + 都把释放命令排入设备线程。窗口关闭先协作停止当前命令,再释放并执行 + `quit()/wait()`,不使用 `terminate()`。 +- 设置页保存/删除设备后发出稳定信号,由主窗口装配到任务页的释放入口。 +- 批量重新上报继续使用原来的独立网络 Worker,不访问 Android 设备。 +- 未修改数据库、Admin 接口、任务状态或 `pdd_data`;真实下单默认开关和不可逆阶段 + 只核单的硬边界保持不变。 + +与建单方案的差异:没有新增单独的执行器文件,而是在现有 +`ClaimTaskWorker/PDDTaskPageEvent` 边界内改成长生命周期实现,减少初级程序员需要追踪 +的类和文件。#109 已证明连接复用无法达到原性能目标,因此本次只确认连接复用和 +线程安全成立,不把端到端性能项写成通过。 + +## 改了哪些 + +- `client/src/pdd_device_service.py`:持久连接、TTL、每任务健康检查、单次重连和线程归属。 +- `client/src/pdd_ui_event.py`:固定 QThread、串行命令路由、停止/释放和窗口关闭流程。 +- `client/src/collect_task_service.py`:正式采集使用当前设备线程绑定的连接服务。 +- `client/src/pdd_u2_purchase_adapter.py`:dry-run/live 采购使用同一线程内连接服务。 +- `client/src/pdd_u2_purchase_reconcile_adapter.py`:不可逆阶段核单使用同一线程内连接服务。 +- `client/src/settings_ui_event.py`、`client/src/ui_main.py`:设备配置变化后通知任务页释放旧连接。 +- `client/test/test_pdd_device_service.py`:连接复用、TTL、serial 变化、单次重连和跨线程拒绝测试。 +- `client/test/test_pdd_ui_event.py`:连续自动获取复用同一固定 QThread 测试。 +- `client/test/test_settings_ui_event.py`:设备配置变化信号测试。 +- `docs/client/02-architecture.md`:记录持久设备线程、90 秒 TTL 和安全释放规则。 + +## 验收结果 + +| 验收标准 | 结果 | +|---|---| +| #109 基线和用户覆盖原 No-Go 门槛的决定已记录 | 通过 | +| 同一 serial 在 90 秒内连续任务只调用一次 `uiautomator2.connect()` | 通过,单元测试及真机只读 5 次验证 | +| Device 的创建、调用和释放固定在同一线程 | 通过 | +| 自动获取、手动重试、采购和核单不会并发控制同一设备 | 通过 | +| 每个任务重新读取应用状态,不复用页面和业务数据 | 通过 | +| TTL、停止、设备配置变化、serial 变化和窗口关闭安全释放 | 通过 | +| 缓存连接健康检查失败后最多重连一次 | 通过 | +| 不可逆阶段后只允许核单,不重新下单 | 通过,既有采购恢复测试覆盖 | +| 热启动阶段中位耗时降低 30% 或 1.5 秒 | 未通过;主要耗时仍是每任务必须执行的 `app_current()` | +| 保留可回退边界,未改变数据库、Admin 和任务数据 | 通过 | +| Client 全量测试、语法和离屏冒烟通过 | 通过 | +| 真实下单仍默认关闭,未执行下单或付款 | 通过 | + +## 测试 + +- 执行的命令: + - `C:/Python310/python.exe -m py_compile src/collect_task_service.py src/pdd_device_service.py src/pdd_u2_purchase_adapter.py src/pdd_u2_purchase_reconcile_adapter.py src/pdd_ui_event.py src/settings_ui_event.py src/ui_main.py` + - `C:/Python310/python.exe -m unittest discover -s test -p "test_*.py"` + - `$env:QT_QPA_PLATFORM="offscreen"; C:/Python310/python.exe -c "from src.ui_main import MainWindow; from PyQt5.QtWidgets import QApplication; app=QApplication([]); w=MainWindow(); print('OK'); w.pddTaskPageEvent.shutdown(); w.settingsPage.eventBinder.shutdown(); app.quit()"` + - `adb devices` + - 真机只读脚本:同一 Wi-Fi serial 连续创建 5 个 `PersistentPddDeviceService` 任务会话,只读取 `app_current()`。 + - `git diff --check` +- 结果:Client 全量 316 项通过;语法、差异检查和离屏主窗口冒烟通过;ADB 设备 + `192.168.0.173:5555` 在线;5 个真机会话只有 1 次底层连接,线程 ID 始终为 + 22788。5 次会话健康检查耗时为 11730.6、10756.5、10589.1、10738.6、 + 10826.3 ms,设备均报告当前包名 `com.android.settings`。 +- **没验证到的部分**:没有领取真实 Admin 任务连续执行完整采集或采购;没有执行 + 真实下单、创建订单或付款;没有在真机等待 90 秒观察 QTimer 到期,而是由单元测试 + 覆盖 TTL;没有在真机主动制造断连、验证码、风控、登录失效或不可逆阶段崩溃。 + +## 遗留问题 + +连接复用已经成立,但没有达到原性能验收值。当前主要瓶颈是该 OPPO/ColorOS 上 +`app_current()` 每次约 10.6 秒且可能错误报告系统设置页。不能为了提速删除每任务 +应用和页面安全校验;若继续优化,应另建应用状态检测诊断工单。 + +## 相关提交 + +- `70cedc3` refactor: 复用持久设备工作线程 (#110)