Files
zt-closet-backend/.codebuddy/plans/service-span-and-async-trace_d93c7ebf.md
T
2026-09-11 01:41:52 +08:00

100 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: service-span-and-async-trace
overview: 给 service 层所有对外入口方法补埋 span(svc.Xxx),并修复 clothes 上传异步 goroutine 的 trace 断链,使调用链可读、异步链路可关联。
todos:
- id: clothes-spans
content: 为 clothes.go 的 6 个入口方法(Upload、ProcessStatusGetByUUID、GetByUUID、UpdateByUUID、DeleteByUUID、List)补埋 svc span
status: completed
- id: clothes-async-trace
content: 修复 clothes.go 异步断链:改造 processImageAsync 签名与 ctx 派生、补 svc.ProcessImageAsync span、更新调用点、新增 otel/trace import
status: completed
dependencies:
- clothes-spans
- id: outfit-closet-collect-like-spans
content: 为 outfit.go、closet.go、collect.go、like.go 的入口方法补埋 svc span 并新增 global import
status: completed
- id: notification-quota-user-goods-horoscope-spans
content: 为 notification.go、quota.go、user.go、goods.go、horoscope.go 的入口方法补埋 svc span 并补充所需 import
status: completed
- id: order-airecommend-spans
content: 为 order.go、airecommend.go 的入口方法补埋 svc span 并新增 global import
status: completed
- id: build-vet-verify
content: 运行 go build ./... 与 go vet ./... 验证编译与静态检查通过
status: completed
dependencies:
- clothes-spans
- clothes-async-trace
- outfit-closet-collect-like-spans
- notification-quota-user-goods-horoscope-spans
- order-airecommend-spans
---
## 用户需求
1. 在 service 层对外入口方法补埋 OpenTelemetry span,使 trace 调用链可读。
2. 修复衣物上传异步 goroutine 的 trace 断链,使抠图、COS 上传、分类、回填等异步 DAO span 能关联回原请求。
## 功能内容
- 为 12 个 service 文件、共 41 个对外入口方法(首字母大写的导出方法)统一补埋 `svc.Xxx` span,命名与现有 `dao.Xxx`、`upload.Xxx` 前缀保持一致。
- 私有辅助方法不埋点,避免产生过深的 span 森林。
- 修复 `processImageAsync` 使用 `context.Background()` 导致异步链路丢失父 trace 的问题,通过 `trace.ContextWithSpanContext` 继承 trace 信息、同时切断取消信号。
- 异步分支补一个 `svc.ProcessImageAsync` span,将异步处理在 trace 中聚合成一个独立分组。
## 视觉/可观测效果
- 在 trace 平台中,每个 HTTP 请求下能看到 `svc.Xxx` 容器 span,其下嵌套对应业务调用的 `dao.Xxx`、`upload.Xxx` span,调用层次清晰。
- 衣物上传后,后台异步处理(抠图、COS、分类、回填)不再生成孤立 trace,而是挂在原请求(或 `svc.ProcessImageAsync`)之下,便于端到端排查。
## Tech Stack
- 语言:Go 1.27
- 可观测:OpenTelemetry Trace(已接入,`global.Tracer`)
- Web 框架:Gin(API 层已由 `otelgin.Middleware` 自动埋 server span,本次不涉及)
## Implementation Approach
采用「只补边界、不埋全程」的埋点策略:
1. service 入口方法方法体开头统一插入:
```
ctx, span := global.Tracer.Start(ctx, "svc.Xxx")
defer span.End()
```
span 名 = `svc.` + 方法名。通过覆盖入口方法,使 DAO/upload 子 span 在 trace 中正确归属到业务动作。
2. 修复异步断链:将 `processImageAsync` 签名改为接收 `parentCtx context.Context`,内部用:
```
ctx, cancel := context.WithTimeout(trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(parentCtx)), 3*time.Minute)
```
继承父 trace 的 span context,但用 `context.Background()` 切断请求 ctx 的取消信号(保证请求结束后 goroutine 仍能运行),再补 `svc.ProcessImageAsync` span 聚合异步分支。
## Implementation Notes
- service 层 span 只做 start/end,不调用 `span.RecordError`:service 方法返回 `*errcode.Error` 且在多个 return 点返回,若记录错误需改成具名返回值,侵入过大;本次目标为调用链可读,span 嵌套与耗时已满足需求。
- 需新增 `global` import 的文件:order.go、goods.go、outfit.go、horoscope.go、collect.go、closet.go、like.go、notification.go;airecommend.go、clothes.go、user.go、quota.go 已导入 `global`。
- clothes.go 需新增 `go.opentelemetry.io/otel/trace` import(go.mod 已包含该依赖)。
- 保持与现有 DAO 埋点风格一致:span 名用 `dao.Xxx`/`upload.Xxx` 相同的大写方法名风格,不引入新的埋点封装或 helper,避免与现有约定不一致。
## Directory Structure
```
internal/service/
├── clothes.go # [MODIFY] 6 个入口方法补 span;processImageAsync 签名改造、trace 传播修复、新增 svc.ProcessImageAsync span、更新调用点、新增 otel/trace import
├── outfit.go # [MODIFY] Create/GetByUUID/UpdateByUUID/List/Delete/Public 补 span;新增 global import
├── closet.go # [MODIFY] Create/Detail/List/Cancel 补 span;新增 global import
├── collect.go # [MODIFY] Collect/List 补 span;新增 global import
├── like.go # [MODIFY] LikeCreate/GetByTargetID 补 span;新增 global import
├── notification.go # [MODIFY] List/GetByUUID/Read/Unread 补 span;新增 global import
├── quota.go # [MODIFY] InfoGetBySelf/FlowList 补 span(global 已导入)
├── user.go # [MODIFY] WxLogin/InfoGetBySelf/ProfileUpdate/RefreshToken 补 span(global 已导入)
├── goods.go # [MODIFY] GetByCode/List 补 span;新增 global import
├── horoscope.go # [MODIFY] GetToday 补 span;新增 global import
├── order.go # [MODIFY] Create/PayNotify/Cancel/List/RefundApply/RefundNotify 补 span;新增 global import
└── airecommend.go # [MODIFY] Create/Save 补 span(global 已导入)
```