diff --git a/GUIDE.md b/GUIDE.md index 55dce62..4574b86 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -513,6 +513,9 @@ type User struct { ### 5.1 初始化缓存 +> **v1.4.0**:App 用户经 `WithRedis()` 启用时,`Init` 自动用 `app.redisManager.Client()` 初始化缓存 +> (走 App 自己的 Redis,多 App 隔离,不串越)。下方 `cache.Init()`(包级)用于 standalone 或回退全局 Redis。 + ```go import "github.com/EthanCodeCraft/xlgo-core/cache" @@ -908,6 +911,12 @@ token := middleware.GetCSRFToken(c) ### 8.4 限流(支持 Redis 分布式限流) +> **v1.4.0**:App 持专属 `RateLimitRegistry`,`Shutdown` 调 `registry.Stop()`(不再调全局 +> `StopRateLimiters`,避免误停其他 App 的限流器)。下方包级 `LoginRateLimit`/`APIRateLimit`/等仍可用 +> (请求时解析全局默认 Registry,单 App 场景无变化)。**多 App per-App 计数隔离**用 +> `app.RateLimitRegistry().LoginRateLimit()` 等 App-bound 中间件(捕获 App 自己的 Registry,不查全局)。 +> **多 App 走各自 Redis** 用 `middleware.NewRedisRateLimiter(..., middleware.WithRedisClient(app.RedisClient()))`。 + ```go // 初始化限流器 middleware.InitRateLimiters() @@ -1213,6 +1222,10 @@ storage: ### 10.3 使用存储 +> **v1.4.0**:App 用户经 `WithStorage()` 启用时,`Init` 自动初始化存储并提升为全局默认;`Shutdown` +> 经 `StorageManager.Close()` 收口(当前 LocalStorage/OSSStorage 无 closeable 资源为 no-op,为未来 +> 驱动预留)。下方 `storage.Init()`(包级)用于 standalone。 + ```go import "github.com/EthanCodeCraft/xlgo-core/storage" @@ -1536,6 +1549,24 @@ count := hub.Count() ## 13. 定时任务 +> **v1.4.0**:App 持专属调度器(实例隔离,多 App 互不污染)。**App 管理的任务用 +> `xlgo.WithCronTask(name, schedule, handler)` 注册**(蕴含启用 cron,`Init` 时注册+启动, +> `Shutdown` 时停止并等待在跑任务退出)。下方包级 `cron.AddTask`/`cron.Start`/`cron.Stop` 仍可用于 +> standalone(无 App)或 `Init` 之后;**`Init` 之前**调包级 `cron.AddTask` 会注册到 init 默认 +> 调度器、被 App swap 丢弃。`app.Scheduler()` 返回 App 调度器,供动态注册与管理 +> (`AddTask`/`RemoveTask`/`RunTask`/`ListTasks`)。 +> +> ```go +> app := xlgo.New(xlgo.WithConfig(cfg), +> xlgo.WithCronTask("cleanup", cron.Every(5*time.Minute), func(ctx context.Context) error { +> return cleanupOldData() +> }), +> xlgo.WithCronTask("daily_report", cron.Daily(2, 0), generateReport), +> ) +> // 动态注册(Init 后):app.Scheduler().AddTask(...) +> if err := app.Run(); err != nil { /* ... */ } +> ``` + ### 13.1 添加任务 ```go @@ -1586,6 +1617,17 @@ scheduler.EnableTask("cleanup") // 启用任务 ## 14. 链路追踪 +> **v1.4.0**:`xlgo.WithTrace()` 把 trace 纳入 App 生命周期--`Init` 按 `config.Trace` 调 +> `trace.Init`、装入 `trace.Middleware`、`Shutdown` 调 `trace.Close` 刷出 span 并释放 exporter +> 后台 goroutine。下方手动 `trace.Init`/`trace.Close`/`trace.Middleware` 仍可用于 standalone +> (无 App)。**trace 不做实例隔离**--OTel `TracerProvider` 是进程级全局单例,多 App 进程共享, +> 任一 `Shutdown` 会关全局导出;多 App 不要同时开 `WithTrace`。 +> +> ```go +> app := xlgo.New(xlgo.WithConfigPath("config.yaml"), xlgo.WithTrace()) +> // config.yaml 配置 trace.enabled / trace.endpoint / trace.exporter_type / trace.sample_ratio ... +> ``` + ### 14.1 初始化 ```go diff --git a/README.md b/README.md index b3b3553..5754e74 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,8 @@ err := userRepo.WithTransaction(ctx, func(txRepo *repository.BaseRepo[model.User ### Redis 缓存 +> **v1.4.0**:App 经 `WithRedis()` 启用时自动用 App 的 Redis 客户端初始化缓存(多 App 隔离,不串越)。下方 `cache.Init()` 用于 standalone。 + ```go // 初始化缓存 cache.Init() @@ -416,6 +418,8 @@ err := cache.WithLockAutoExtend(ctx, key, 30*time.Second, 10*time.Second, func(c ### Redis 分布式限流 +> **v1.4.0**:多 App 走各自 Redis 用 `middleware.NewRedisRateLimiter(..., middleware.WithRedisClient(app.RedisClient()))`。 + ```go // 内存限流(单实例) r.Use(middleware.CustomRateLimit(100, time.Minute)) @@ -528,6 +532,11 @@ hub.Broadcast([]byte("广播消息")) ### 定时任务 +> **v1.4.0**:App 持专属调度器(实例隔离)。**App 管理的任务用 `xlgo.WithCronTask(name, schedule, handler)` +> 注册**(蕴含启用 cron,`Init` 时注册+启动,`Shutdown` 时停止)。下方包级 `cron.AddTask`/`cron.Start` +> 仅用于 standalone(无 App)或 `Init` 之后;**`Init` 之前**调包级 `cron.AddTask` 会注册到 init 默认 +> 调度器、被 App swap 丢弃。`app.Scheduler()` 供动态注册与管理。 + ```go // 每隔 5 分钟执行 cron.AddTask("cleanup", cron.Every(5*time.Minute), func(ctx context.Context) error { @@ -620,6 +629,8 @@ userType := middleware.GetUserType(c) ### 限流中间件 +> **v1.4.0**:App `Shutdown` 自动 `registry.Stop()`(不再调全局 `StopRateLimiters`,避免误停其他 App)。多 App per-App 计数隔离用 `app.RateLimitRegistry().LoginRateLimit()` 等 App-bound 中间件。 + ```go // 登录限流(每分钟 10 次) r.POST("/login", middleware.LoginRateLimit(), func(c *gin.Context) { @@ -842,6 +853,22 @@ docker run -d -p 8080:8080 xlgo-app:latest > 完整变更历史见 [CHANGELOG.md](./CHANGELOG.md)。 +### v1.4.0 (2026-07-12) + +> **instance+facade 一致性收尾**:cron/storage/cache/ratelimit 实例化(App 持 per-App 实例 + `SwapDefault*` + 包级 facade 代理,照 `database.Manager`/`jwt.Manager` 模式),消除单进程多 App 互相污染;trace 纳入 App 生命周期(`WithTrace`);删除 `WithoutWire` 空函数。`go vet` + `go build` + `go test -race ./...` 全绿。完整变更见 [CHANGELOG.md](./CHANGELOG.md)。 + +主要破坏性变更(升级前必读): + +- **`xlgo.WithoutWire()` 删除**:v1.1.0 wire 包删除后遗留的空 no-op,直接删除调用即可(无行为变化)。 +- **`cron.AddTask` 在 `App.Init` 之前注册失效**:App 持专属调度器,pre-Init 包级 `cron.AddTask` 注册到 init 默认调度器、被 App swap 丢弃。改用 `xlgo.WithCronTask(name, schedule, handler)`(或 Init 后 `app.Scheduler().AddTask`)。 +- **`middleware.StopRateLimiters` 语义收窄**:仅停默认 Registry;App `Shutdown` 调 `app` 自己的 `registry.Stop()`,不再误停其他 App 限流器。 +- **`commitReplacedResources` 不再关闭 `previousDB`/`previousRedis`/`loggerSnapshot`**:多 App 下 previous 可能是另一 App 的活跃资源(致 `redis: client is closed` / logger writer 误杀)。单 App 无影响(init 默认无资源)。 +- **cache/ratelimit redis 注入**(jwt 模型):`cache.NewRedisCacheWithRedis`/`CacheManager.InitWithRedis`;`middleware.WithRedisClient`。 + +新增:`WithTrace`/`WithCronTask`;`app.Scheduler()`/`Cache()`/`RedisClient()`/`RateLimitRegistry()`;`cron/storage/cache/middleware` 各 `SwapDefault*`;`config.TraceConfig`;`middleware.RateLimitRegistry` + App-bound 限流中间件;`storage.StorageManager.Close()`。 + +升级:`go get github.com/EthanCodeCraft/xlgo-core@v1.4.0`(⚠️ 含破坏性变更,详见 CHANGELOG 迁移说明) + ### v1.2.0 (2026-07-04) > **破坏性版本**:4 轮对抗性评审(deepseek / GLM / Claude / 终审)收口的全部 CRITICAL/HIGH/MEDIUM 修复 + 主线A 包级可变全局并发治理统一。`go vet` + `go build` + `go test -race ./...` 全绿。完整变更见 [CHANGELOG.md](./CHANGELOG.md)。