系列09-Playwright UI 自动化平台怎么设计?MQ 调度与 Runner 执行架构
系列09-Playwright UI 自动化平台怎么设计?MQ 调度与 Runner 执行架构
本地用 Playwright 写脚本很顺;做成团队平台会撞上四类硬问题:
- 浏览器不能长期跑在 FastAPI worker 里(资源、隔离、Linux 无桌面)
- 多台 Windows/Mac 测试机如何认领任务、不串台
- 截图/视频存哪、报告如何三级汇总
- Runner 在公网如何安全连 MQ/Redis/MinIO
BrickCore 的答案:平台编排 + RabbitMQ 解耦 + Runner 执行 Playwright。本文基于 CE 可读源码讲架构;引擎WebEngine闭源,但MQ 协议与调度逻辑完全开源。
演示与源码
| 地址 | |
|---|---|
| 功能演示 | http://43.142.83.156/showcase/ (「UI 录制」「UI Agent 生成步骤」等录屏;平台 admin / BrickCore123456) |
| 开源仓库 | https://gitee.com/BanZhuanKeOrz/BrickCore |
| Runner 安装包 | https://gitee.com/BanZhuanKeOrz/BrickCore/releases |
试跑页:http://43.142.83.156/showcase/demo-ui.html(demo / demo123)。AI 定位器自愈见系列06;本文聚焦调度与执行架构。
一、为什么 UI 执行必须外置
| Web 内嵌浏览器 | 后果 |
|---|---|
| 与 API/压测抢 CPU | UI 任务饿死或拖垮接口回归 |
| 容器无 DISPLAY | Xvfb 稳定性差 |
| 用户步骤任意 URL | 安全隔离难 |
| Web 水平扩容 | 与浏览器进程无关,浪费 |
结论:调度在平台,执行在 Runner(桌面或专用机)。
二、平台 vs Runner 职责边界
| 平台(FastAPI + Vue) | Runner(BrickCoreRunner) | |
|---|---|---|
| 步骤 JSON 编辑 / 录制入口 | ✅ | ❌ |
| 计划触发、权限、报告 | ✅ | ❌ |
| Playwright 执行 | ❌ | ✅ |
| 截图/视频上传 MinIO | 存 URL | ✅ 上传 |
| 设备上线、心跳 | 设备管理 | ✅ |
| AI 自愈 LLM 调用 | Backend API | 失败时 POST internal |
三、四层数据模型
Case(steps JSON:keyword / method / params / desc) → Suite(用例顺序、stop_on_failure、setup SQL) → Task/Plan(多套件、定时 cron) → Execution(Plan / Suite / Case 三级执行记录)步骤示例:
{"keyword":"点击元素","method":"click_ele","params":{"locator":"get_by_role=button,name=提交","timeout":20000},"desc":"点击提交按钮"}支持条件分支、步骤片段、数据库断言(Backend 代跑 SQL,Runner 不持库密码)。
四、端到端时序
用户触发 UI 计划/套件/单用例 → 平台创建 *Execution 记录(status=running) → resolve_locator_heal、headless 等写入 env_config → dispatch_to_device(device_id) — 校验设备「在线」且含 web 引擎 → MQ send_test_task(env_config, run_suite, device_id) → Runner 消费 → Playwright 逐步执行 → HTTP post_results(截图 URL、步骤日志、locator_healed) → 平台汇总报告,可选邮件推送┌──────────────┐ queue=device_id ┌─────────────────┐ │ 平台 FastAPI │ ───────────────► │ Runner Playwright│ │ MySQL 记录 │ ◄─────────────── │ MinIO 截图 │ └──────────────┘ HTTP 回写 └─────────────────┘ │ ▲ └──────── RabbitMQ / Redis ──────────┘五、源码视角:发任务与队列模型
5.1 落库再发 MQ
# routers/ui/exec.pyasyncdefdispatch_to_device(env_payload,suite_payload,device_id):device=awaitDevice.get_or_none(id=device_id)ifnotdeviceordevice.status!="在线":returnFalsemq.send_test_task(env_payload,suite_payload,device_id)先写 Execution 再发消息:Runner 回写时有关联 ID;设备离线则不分发,避免消息进无人队列。
5.2 队列名 = device_id
# core/mq_producer.pyself.channel.queue_declare(queue=device_id,durable=True)self.channel.basic_publish(exchange='',routing_key=device_id,body=msg,properties=pika.BasicProperties(delivery_mode=2))| 设计 | 作用 |
|---|---|
routing_key=device_id | 每台 Runner 独占队列,不串台 |
durable=True+delivery_mode=2 | Broker 重启不丢队列/消息 |
5.3 MQ 消息体(自建 Runner 可对照)
{"env_config":{"base_url":"https://demo.example.com","headless":true,"ai_heal_enabled":true,"project_id":1,"environment_id":2},"run_suite":{"suite_id":12,"case_id":101,"cases":[{"case_id":101,"steps":[...]}]}}六、Runner 消费与经典踩坑
runner/tools/mq_consumer.py:
# IO 线程收到消息 → 尽快 basic_ack# Playwright 在工作线程 execute → 禁止在工作线程 ackdef_process_message(...):runner=Runner(env_config,run_suite)result=runner.run()self._save_result(run_suite,result)现象:用例实际成功,平台一直running,日志MQ 连接丢失。
原因:PikaBlockingConnection跨线程 ack。
处理:CE 安装包已在 IO 线程 ack;自建 Runner 须遵守同样约束。
失败步骤若开AI 自愈,basecase.py捕获异常 →try_heal_step→ 重试本步(详见系列06)。
七、结果回写与安全
| 模式 | 认证 | 场景 |
|---|---|---|
| 桌面客户端 connect | X-Runner-Token | 测试同学本机 Runner |
| 演示机 / 无头 | X-Internal-Token | /runner/results/internal |
connect 模式(routers/runner/connect.py):provision_device_middleware为每设备独立 MQ/Redis 账号,Runner不拿业务库密码。
八、RabbitMQ、Redis、MinIO 与部署
| 组件 | 作用 |
|---|---|
| RabbitMQ | 任务队列(25672) |
| Redis | 执行日志流、实时进度(26379) |
| MinIO | 截图/视频;公网 URL 需配MINIO_PUBLIC_ENDPOINT(9200) |
Docker 全栈部署时,Runner 在容器外连公网中间件——安全组除 80 外须放行25672 / 26379 / 9200,否则任务永久排队。
九、Runner 生命周期(实操)
- 安装BrickCoreRunner(Release,注意 arm64/intel)
- 配置平台 URL,登录,上线→ 设备管理显示「在线」
- UI 模块运行套件/计划,选该device_id
- 解压路径勿含中文/空格
十、与 Selenium Grid / 纯脚本对比
| 纯 Playwright 脚本 | Selenium Grid | 平台 + Runner | |
|---|---|---|---|
| 维护载体 | Git 代码 | Grid 节点 | Web 步骤 JSON |
| 非开发参与 | 难 | 中 | 较易(录制/Agent) |
| 报告 | 自建 | 部分 | 三级落库 + HTML |
| 水平扩展 | CI shard | 加 Grid | 加 Runner 机器 |
| AI 自愈 | 自建 | 无 | 平台 Backend+Runner |
十一、CE 开源边界
| Gitee CE 可读 | 安装包闭源 |
|---|---|
backend调度、MQ、设备、报告 | runner/WebEngine引擎 |
frontend步骤编辑器 | Runner 打包脚本 |
MQ 消息结构、runner/connect | — |
全功能可体验;二次开发引擎需 Pro/商业授权或自研 Playwright 层。
十二、常见排错
| 现象 | 处理 |
|---|---|
| 任务一直排队 | Runner 未上线;MQ 端口未开 |
| 设备离线 | 心跳超时;重启 Runner |
| 报告无截图 | MinIO 公网地址/9200 安全组 |
| 用例成功平台 running | MQ 跨线程 ack(见 §6) |
| 发错机器 | 检查选用的 device_id |
十三、小结
- UI 平台 =编排 + 记录;Runner =Playwright 执行。
- MQ 按设备队列分发,易水平加机器。
- MinIO统一截图;connect模式隔离中间件账号。
- 架构可复用到任意「Web 测管 + 远程执行器」方案。
附录 A:源码文件索引
| 顺序 | 文件 | 关注点 |
|---|---|---|
| 1 | routers/ui/exec.py | Execution、dispatch_to_device |
| 2 | core/mq_producer.py | send_test_task |
| 3 | routers/runner/connect.py | connect bundle、中间件隔离 |
| 4 | core/runner_results.py | 结果落库、通知 |
| 5 | runner/tools/mq_consumer.py | 消费、ack 策略 |
| 6 | runner/tools/runner_api.py | post_results |
支持与交流
- 演示:http://43.142.83.156/showcase/ · 源码:https://gitee.com/BanZhuanKeOrz/BrickCore
- 觉得有用欢迎Star⭐,问题评论区留言或 Gitee Issues
