feat(compare/coupon): trace_id 统一由后端签发,前端不再本地生成 #210

Merged
marco merged 2 commits from feat-unify-trace-id-backend-issued into main 2026-07-31 23:11:36 +08:00
Owner

一次比价/领券的 trace_id 改由后端签发,让前端 SLS 运行日志(trace_id 索引列)、
app-server 比价记录与领券流水、pricebot trace 目录/run.log/trace_url 全链共用同一个
id 查到底(此前前端各业务自己 randomUUID,虽同链但非后端签发、也无单一签发点)。

  • POST /api/v1/compare/start(预占额度,任务第一个请求,签发与建 running 行合一):
    请求 trace_id 改可选,缺省时服务端签发 uuid;响应新增 trace_id 字段返回(签发的或
    回显客户端带来的)。客户端带值则沿用——老客户端兼容 + 同 trace 重试幂等。
  • POST /api/v1/coupon/session:started 帧缺 trace_id 时签发并随响应返回(签发不依赖
    写库成功);非 started 帧缺 trace_id 不签发、不写库(收尾没有 id 只能是异常调用,
    签发新 id 只会造出查不到发起信息的孤儿行)。新增 CouponSessionOut 响应模型——原
    dict[str,bool] 注解无法承载字符串 trace_id,FastAPI 响应校验会炸。
  • 测试:更新 2 处旧断言(响应体多出 trace_id 字段),新增 compare 不带 id 签发用例 +
    coupon started 签发/回显、终尾缺 id 跳过写库 3 个用例。全量 30 passed + ruff clean。

配合 shaguabijia-app-android 同名分支 feat-unify-trace-id-backend-issued 的前端换源改动。

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

一次比价/领券的 trace_id 改由后端签发,让前端 SLS 运行日志(trace_id 索引列)、 app-server 比价记录与领券流水、pricebot trace 目录/run.log/trace_url 全链共用同一个 id 查到底(此前前端各业务自己 randomUUID,虽同链但非后端签发、也无单一签发点)。 - POST /api/v1/compare/start(预占额度,任务第一个请求,签发与建 running 行合一): 请求 trace_id 改可选,缺省时服务端签发 uuid;响应新增 trace_id 字段返回(签发的或 回显客户端带来的)。客户端带值则沿用——老客户端兼容 + 同 trace 重试幂等。 - POST /api/v1/coupon/session:started 帧缺 trace_id 时签发并随响应返回(签发不依赖 写库成功);非 started 帧缺 trace_id 不签发、不写库(收尾没有 id 只能是异常调用, 签发新 id 只会造出查不到发起信息的孤儿行)。新增 CouponSessionOut 响应模型——原 dict[str,bool] 注解无法承载字符串 trace_id,FastAPI 响应校验会炸。 - 测试:更新 2 处旧断言(响应体多出 trace_id 字段),新增 compare 不带 id 签发用例 + coupon started 签发/回显、终尾缺 id 跳过写库 3 个用例。全量 30 passed + ruff clean。 配合 shaguabijia-app-android 同名分支 feat-unify-trace-id-backend-issued 的前端换源改动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
marco added 1 commit 2026-07-31 21:38:09 +08:00
一次比价/领券的 trace_id 改由后端签发,让前端 SLS 运行日志(trace_id 索引列)、
app-server 比价记录与领券流水、pricebot trace 目录/run.log/trace_url 全链共用同一个
id 查到底(此前前端各业务自己 randomUUID,虽同链但非后端签发、也无单一签发点)。

- POST /api/v1/compare/start(预占额度,任务第一个请求,签发与建 running 行合一):
  请求 trace_id 改可选,缺省时服务端签发 uuid;响应新增 trace_id 字段返回(签发的或
  回显客户端带来的)。客户端带值则沿用——老客户端兼容 + 同 trace 重试幂等。
- POST /api/v1/coupon/session:started 帧缺 trace_id 时签发并随响应返回(签发不依赖
  写库成功);非 started 帧缺 trace_id 不签发、不写库(收尾没有 id 只能是异常调用,
  签发新 id 只会造出查不到发起信息的孤儿行)。新增 CouponSessionOut 响应模型——原
  dict[str,bool] 注解无法承载字符串 trace_id,FastAPI 响应校验会炸。
- 测试:更新 2 处旧断言(响应体多出 trace_id 字段),新增 compare 不带 id 签发用例 +
  coupon started 签发/回显、终尾缺 id 跳过写库 3 个用例。全量 30 passed + ruff clean。

配合 shaguabijia-app-android 同名分支 feat-unify-trace-id-backend-issued 的前端换源改动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member

🤖 review-pr 深审结论

🟢 可合并 · 置信度 0.9 —— trace_id 后端签发设计周到(兼容/幂等/孤儿防护),测试通过。须配套 android#380

改动:compare/start + coupon/session 的 trace_id 改后端签发,前端不再本地 randomUUID。

正确性核对(合并后)

  • compare/starttrace_id = payload.trace_id or uuid4()——缺省签发、客户端带值沿用(老客户端兼容 + reserve_daily_start 按 trace_id 去重=重试幂等)、响应返回 trace_id。
  • coupon/session:started 帧签发(不依赖写库成功);非 started 帧缺 id 不签发不写库(防「查不到发起信息的孤儿行」);if trace_id: 守卫 merge_session_platform_success
  • CouponSessionOut 响应模型:原 dict[str,bool] 注解装不下 trace_id 字符串会让 FastAPI 响应校验炸,新增模型正确。
  • 铁律1:main 未改本 PR 文件。

构建/测试(实跑 .venv 合并后) test_compare_daily_limit + test_coupon_session_issue 7 passed(compare 签发 + coupon started 签发/回显/终尾跳过写库)。

⚠️ 配套 android#380:响应新增 trace_id 字段供前端换源(前端改用后端签发的、不再本地生成)。审 #380 时核对前端消费。

风险 🟢

🤖 review-pr 自动深审 @marco

## 🤖 review-pr 深审结论 🟢 **可合并** · 置信度 0.9 —— trace_id 后端签发设计周到(兼容/幂等/孤儿防护),测试通过。**须配套 android#380**。 **改动**:compare/start + coupon/session 的 trace_id 改后端签发,前端不再本地 randomUUID。 **正确性核对(合并后)** - **compare/start**:`trace_id = payload.trace_id or uuid4()`——缺省签发、客户端带值沿用(老客户端兼容 + `reserve_daily_start` 按 trace_id 去重=重试幂等)、响应返回 trace_id。 - **coupon/session**:started 帧签发(**不依赖写库成功**);非 started 帧缺 id **不签发不写库**(防「查不到发起信息的孤儿行」);`if trace_id:` 守卫 `merge_session_platform_success`。 - **CouponSessionOut 响应模型**:原 `dict[str,bool]` 注解装不下 trace_id 字符串会让 FastAPI 响应校验炸,新增模型正确。 - 铁律1:main 未改本 PR 文件。 **构建/测试(实跑 .venv 合并后)**:✅ `test_compare_daily_limit` + `test_coupon_session_issue` **7 passed**(compare 签发 + coupon started 签发/回显/终尾跳过写库)。 **⚠️ 配套 android#380**:响应新增 `trace_id` 字段供前端换源(前端改用后端签发的、不再本地生成)。审 #380 时核对前端消费。 风险 🟢。 — 🤖 review-pr 自动深审 @marco
marco added 1 commit 2026-07-31 23:08:47 +08:00
对齐 compare 链路(_forward 的 setdefault 注入,每步响应都带 trace_id):coupon_step
透传响应在 resp.json() 后 setdefault 注入本次任务 trace_id,客户端任一帧都能从响应
拿到全链 id。**只回显请求里带的、不 mint**——step 是循环接口,每帧签新 id 会把一次
任务打散;领券 trace_id 的唯一签发点保持在 /coupon/session (status=started)。带
isinstance dict + 非空 trace_id 双防御(pricebot 响应顶层本无 trace_id 字段,setdefault
不会覆盖任何上游值)。

顺手修复 test_coupon_proxy.py 一个 pre-existing 红测试:coupon_step 转发早已改为
content=raw 原始字节透传,但 fake_post 仍只捕获 json= 参数 → captured["json"] 恒
None、body 转发断言一直失败(git stash 验证不带本轮改动同样红)。fake 改捕 content、
断言按字节 json.loads 后对比;transparently-passes-through 断言更新为"透传 + 顶层
回显 trace_id"新契约。

领券相关测试 22 passed。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
marco merged commit 0fc8521c3b into main 2026-07-31 23:11:36 +08:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WonderableAI/shaguabijia-app-server#210