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

5.8 KiB
Raw Permalink Blame History

name, overview, todos
name overview todos
service-span-and-async-trace 给 service 层所有对外入口方法补埋 span(svc.Xxx),并修复 clothes 上传异步 goroutine 的 trace 断链,使调用链可读、异步链路可关联。
id content status
clothes-spans 为 clothes.go 的 6 个入口方法(Upload、ProcessStatusGetByUUID、GetByUUID、UpdateByUUID、DeleteByUUID、List)补埋 svc span completed
id content status dependencies
clothes-async-trace 修复 clothes.go 异步断链:改造 processImageAsync 签名与 ctx 派生、补 svc.ProcessImageAsync span、更新调用点、新增 otel/trace import completed
clothes-spans
id content status
outfit-closet-collect-like-spans 为 outfit.go、closet.go、collect.go、like.go 的入口方法补埋 svc span 并新增 global import completed
id content status
notification-quota-user-goods-horoscope-spans 为 notification.go、quota.go、user.go、goods.go、horoscope.go 的入口方法补埋 svc span 并补充所需 import completed
id content status
order-airecommend-spans 为 order.go、airecommend.go 的入口方法补埋 svc span 并新增 global import completed
id content status dependencies
build-vet-verify 运行 go build ./... 与 go vet ./... 验证编译与静态检查通过 completed
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 中正确归属到业务动作。

  1. 修复异步断链:将 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 已导入)