100 lines
5.8 KiB
Markdown
100 lines
5.8 KiB
Markdown
---
|
||
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 已导入)
|
||
``` |