Files
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

3.9 KiB

AirShelf/core 性能验证闸(perf-probe)

ralph-loop(或人工)当 pass/fail 闸用的性能回归探针。全绿 → 退出码 0;任一硬闸不过 → 退出码 1 + PERF-PROBE: FAIL

一句话目的

逐页 + 逐接口验证「访问变快了 / 重复请求没了 / 但功能没改崩」。改性能时反复跑它,直到全绿。

怎么跑

先起前后端(后端 :8010 连真实 MySQL;前端 vite dev 必须带 /api 代理):

# 后端(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 即时生效。