Files
cmautobuy/docs/task/110-持久设备工作线程复用uiautomator2会话.md
T
2026-08-10 18:01:50 +08:00

6.6 KiB
Raw Blame History

110 使用持久设备工作线程跨任务复用 uiautomator2 会话

背景与目标

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)