Files
yingqing/core/qa/function-audit/PERF-GATE.md
T
zycandClaude Opus 4.8 1ff7be2b56 perf(core): assets/ledgers 列表 defer 掉 AITask 巨型 payload 列,根治取全部资产 60s+ 慢查询
- /api/assets/ 列表 select_related('origin_task__project') 为解析资产归属商品,
  会把每个资产关联 AITask 的 request_payload/response_payload(完整 AI 请求/响应 JSON)
  整行拖出 → 取全部 200 资产实测 >60s 超时,数据越多越慢(用户报的「刷新越来越卡」)。
  加 .defer 这两列后 0.76s,product 仍正常解析、序列化 0 额外查询。
- billing/ledgers 同模式补 .defer(task payload)。ai/billing.summary 早已 defer,assets/ledgers 本是漏网。
- 附 qa/function-audit/perf-probe.mjs 性能验证闸 + PERF-GATE.md(API 确定性断言+浏览器功能守护)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:48:15 +08:00

63 lines
3.9 KiB
Markdown

# AirShelf/core 性能验证闸(perf-probe)
**ralph-loop**(或人工)当 pass/fail 闸用的性能回归探针。全绿 → 退出码 0;任一硬闸不过 → 退出码 1 + `PERF-PROBE: FAIL`
## 一句话目的
逐页 + 逐接口验证「访问变快了 / 重复请求没了 / 但功能没改崩」。**改性能时反复跑它,直到全绿。**
## 怎么跑
先起前后端(后端 `:8010` 连真实 MySQL;前端 vite dev **必须带 /api 代理**):
```bash
# 后端(backend/)
DB_ENGINE=mysql .venv/bin/python manage.py runserver 127.0.0.1:8010 --noreload
# 前端(frontend/)—— 记下它实际监听的端口(可能是 5173/5174)
npm run dev
# 探针(qa/function-audit/)
node perf-probe.mjs --base http://127.0.0.1:5174 # 改成前端实际端口
node perf-probe.mjs --base http://127.0.0.1:5174 --only dashboard,projects
node perf-probe.mjs --base http://127.0.0.1:5174 --headed # 看着跑
```
默认演示账号 `e2e-20260529-0806@airshelf.test` / `demo12345`;也可 `--token <TOKEN>` 免登录。
## 闸怎么判(两层)
### 硬闸(确定性,挂 pass/fail)
1. **API 级:列表接口必须遵守 `page_size`** —— `?page_size=200` 要全部一页拉得到时,`next` 必须为 `null`、条数 = `count`
*当前根因*:`/api/assets/` 无视 `page_size=200`,死按 20 条/页返回 → 前端 `allAssets` 被迫并行翻 N 页(资产越多页越多)。
2. **浏览器级:任意页面不得出现资产分页瀑布**(`/api/assets/?page=2…`)。这是上面那条的直接症状。
3. **功能守护**:每页必须真渲染(没掉回登录页)、所有接口 `< 400`、bootstrap 必须在 25s 内发起(否则=后端慢到没加载出来,判失败防假通过)。
> 为什么 API 检查 + 浏览器双保险:浏览器按时序数瀑布会被后端延迟抖动影响(慢时漏抓)。API 断言与时序无关、永不抖,是真正的硬闸;浏览器只作功能守护 + 佐证。
### 软提示(打印不挂闸,留给架构决策)
- **接口延迟**:本地连远程 MySQL 每次握手 ~1.6s,绝对 ms 天然抖,不宜当硬闸;但打印出来暴露**疑似 N+1 的慢接口**(基线里 `/api/projects/` ~2s、`/api/ops/notifications/` ~1.4s,大概率缺 `select_related/prefetch_related`)。
- **首屏接口数超预算**:每页 bootstrap 拉了 ~9 个全局接口(products/projects/assets/billing/trend/members/models/tasks/notifications),且**每个路由都重拉一遍**——连 `/account` 这种用不到的页也拉。这是架构性过量拉取,**怎么改属设计决策**(懒加载 / 按页取数 / 引入 react-query 缓存层),不由闸强判,见下。
## 基线(2026-06-17,优化前)
-`/api/assets/` page_size 未生效(count=194 → 返回 20、next 有)→ **根因**
- ❌ dashboard / projects / account 等出现 9 页资产瀑布。
-`/api/projects/` ~2s、`/api/ops/notifications/` ~1.4s(疑似 N+1)。
- ⚠ 每页首屏 9~18 个接口(bootstrap 每页重拉)。
- ✅ 全部页面功能正常、无接口报错。
## 优化方向(供参考,不替代设计决策)
1. **修 `page_size` 根因(后端)**:让 `/api/assets/` 真正应用 `AssetPagination`(`max_page_size=200`)。这一条修好,前端瀑布自动消失。
2. **修 `allAssets` 兜底(前端 `src/api.ts`)**:别用 `results.length` 反推页数;按 `count` + 真实 `page_size` 算,或直接跟 `next`
3. **慢接口补 ORM**:`/api/projects/``/api/ops/notifications/` 等加 `select_related/prefetch_related`、确认有分页。
4. **(设计决策)bootstrap 瘦身**:全局只加载真正全站要用的;各页数据按需懒加载 + 缓存,避免每路由重拉 9 个接口。**此项请人工拍板方案再做。**
## 给 ralph 的硬规矩
- 严禁删功能换性能;严禁为过闸放宽断言阈值或把检查注释掉。
- 每轮改完必须重跑 `node perf-probe.mjs --base <前端端口>`,全绿(`PERF-PROBE: PASS`)才算完成。
- 改后端任务/接口代码后注意:本地不起 worker,纯接口改动 runserver 即时生效。