Skip to content

v1.4.0

Latest

Choose a tag to compare

@EthanCodeCraft EthanCodeCraft released this 13 Jul 08:57

v1.4.0 - instance+facade 一致性收尾

把 cron/storage/cache/ratelimit 四个"纯全局"包按 database.Manager/jwt.Manager 模式实例化,trace 纳入 App 生命周期,清理 WithoutWire 技术债。单进程多 App 部署成为一等公民。

为什么发这个版本

database.Manager/logger.LogManager/config.Manager 早已是"实例 + 全局默认 facade"模式,但 cron/storage/cache/ratelimit 仍是纯全局--App 不持 per-App 实例,只绑包级全局 facade。后果:

  • 多 App 互相污染:App A Shutdown 会停掉 App B 的 cron 调度器与限流器;App B Init 覆盖 App A 的 storage driver;cache/ratelimit 硬编码 database.GetRedis(),多 App 下 A 的缓存读到 B 的 Redis。
  • trace 未纳生命周期trace.Close 从未被调用,OTel exporter 后台 goroutine/连接泄漏。
  • WithoutWire 空函数技术债:v1.1.0 删 wire 包后遗留的 no-op,违反框架"不保留 deprecated wrapper"纪律。

本版本收尾这四包的实例化,补齐 trace 生命周期,并修复连带的多 App 跨 App 误杀问题。

⚠️ 破坏性变更(升级前必读)

1. xlgo.WithoutWire() 删除

v1.1.0 删 wire 包后遗留的空 no-op,全仓无引用。直接删除调用即可,无行为变化

2. cron.AddTask(...)App.Init 之前注册不再生效

App 现持专属调度器,Init 时创建并提升为全局默认。pre-Init 调包级 cron.AddTask 会注册到 init 默认调度器、被 App swap 丢弃。

// ❌ 旧(pre-Run 全局注册,v1.4.0 失效)
cron.AddTask("cleanup", cron.Every(5*time.Minute), cleanup)
app := xlgo.New(xlgo.WithConfig(cfg), xlgo.WithCron())

// ✅ 新(WithCronTask 注册到 App 调度器,蕴含启用 cron)
app := xlgo.New(xlgo.WithConfig(cfg),
    xlgo.WithCronTask("cleanup", cron.Every(5*time.Minute), cleanup),
)

post-Init 的包级 cron.AddTask 仍可用(代理到 App 调度器);standalone(无 App)用法不变。

3. middleware.StopRateLimiters() 语义收窄

仅停默认 Registry 的限流器。App Shutdown 改调自己的 registry.Stop()不再误停其他 App

4. commitReplacedResources 不再关闭 previousDB/previousRedis/loggerSnapshot

多 App 下 "previous" 可能是另一个 App 的活跃资源,关闭致 redis: client is closed 或 logger writer 误杀。单 App 无影响(init 默认无资源)。手动 database.InitRedis 后再 App.Init 的旧 client 关闭由用户负责。

5. cache/ratelimit redis 注入(签名扩展)

  • cache:新增 NewRedisCacheWithRedis(client) / CacheManager.InitWithRedis(client) / SwapDefaultCacheManager(m)NewRedisCache() 仍存在(standalone)。
  • middlewareRedisRateLimiter 新增 WithRedisClient(client) 选项。

✨ 新增

WithTrace - trace 纳入 App 生命周期

app := xlgo.New(xlgo.WithConfigPath("config.yaml"), xlgo.WithTrace())
# config.yaml
trace:
  enabled: true
  service_name: my-service
  endpoint: localhost:4318
  exporter_type: otlp-http   # otlp-http / otlp-grpc / stdout
  sample_ratio: 1.0
  # insecure: true           # 明文 collector 需开启
  # propagator: w3c           # w3c(默认) / b3 / jaeger

Inittrace.Init + 装 trace.MiddlewareShutdowntrace.Close(此前从未调用,致 exporter 泄漏)。不做实例隔离--OTel TracerProvider 是进程级全局单例,多 App 不要同时开 WithTrace

App-bound 限流中间件(多 App per-App 计数隔离)

// 包级 LoginRateLimit() 多 App 下仅绑最后 Init 的 App;
// 用 app-bound 实现真正的 per-App 计数隔离:
app.GetRouter().GET("/login", app.RateLimitRegistry().LoginRateLimit(), handler)

新增 App getter(绕过全局 facade,直取 App 实例)

  • app.Scheduler() - cron 调度器
  • app.Cache() - 缓存服务
  • app.RedisClient() - Redis 客户端(注入 RedisRateLimiter 等)
  • app.RateLimitRegistry() - 限流器 Registry

其它

  • cron/storage/cache/middlewareSwapDefault*(App Init 失败回滚用)
  • config.TraceConfig + Config.Trace 字段
  • storage.StorageManager.Close() - 闭合 Init/Close 生命周期(io.Closer 断言,当前 no-op,为未来驱动预留收口点)

🐛 修复

  • 多 App cron 隔离:App A Shutdown 不再停掉 App B 的调度器。
  • 多 App storage/cache 隔离:App B Init 不再覆盖 App A 的 driver / cache redis;cache 不再硬编码全局 Redis。
  • 多 App 限流器:App A Shutdown 不再重置 App B 的 loginLimiter 计数(原 StopRateLimiters 全局置 nil 致 B 下次请求懒创建新 limiter、计数清零,稳态客户端借 A 的 Shutdown 窗口绕过限流)。
  • trace exporter 泄漏App.Shutdown 现调 trace.Close
  • 多 App logger/redis 跨 App 误杀commitReplacedResources 不再关闭非己所有的 previous 资源。

多 App 边界(使用前知悉)

说明
包级限流 facade LoginRateLimit 等多 App 下仅绑最后 Init 的 App;per-App 计数隔离用 app.RateLimitRegistry()
CustomRateLimit(包级) 首请求须在 Init 后(否则 cleanup goroutine 泄漏);app-bound 路径无此问题
trace 进程全局共享,多 App 任一 Shutdown 关全局导出
StorageManager.Close 当前 no-op(oss.Client 无 Close),未来驱动实现 io.Closer 即自动收口

✅ 验证

  • go build + go vet + go test -race ./... 全绿。
  • 新增契约测试:trace lifecycle、storage/cron/cache/ratelimit 实例隔离 + 多 App 不串 + rollback 还原、cache 多 Redis 隔离、ratelimit 多 App Shutdown 不重置计数 + per-App 计数隔离、storage Close 各路径。
  • 独立对抗性复审:无 CRITICAL/HIGH,发现项全部处置。

升级

go get github.com/EthanCodeCraft/xlgo-core@v1.4.0

⚠️ 含破坏性变更,升级前请阅读"破坏性变更"并按迁移示例调整。完整变更见 CHANGELOG.md