first commit

This commit is contained in:
2026-09-11 01:41:52 +08:00
commit 9f22e6ccae
263 changed files with 28935 additions and 0 deletions
@@ -0,0 +1,100 @@
---
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 已导入)
```