// Copyright 2026 tamakyi. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package shared import ( "context" "time" "github.com/redis/go-redis/v9" ) // RedisPingTimeout 是启动期探活的总超时。 // 刻意短:启动阶段卡住比启动失败更难排查,3 秒足够区分「连不上」与「慢」。 const RedisPingTimeout = 3 * time.Second // PingRedis 在启动时探一次 Redis 连通性,用于 fail fast。 // // 为什么必须做这件事:session 建在 Redis 上(route.go 的 sessioner),而 // flamego/session 对 load 错误是直接 panic,被 Recovery 兜成 500 —— // 也就是 **Redis 一宕,每个请求都 500,包括完全未登录的访客**。 // 等到第一个真实请求才暴露时,运维看到的现场是「站点全 500」, // 很难第一时间联想到 Redis;启动期直接报错退出,信号干净得多。 // // 同时显式设置读写超时:go-redis 默认 Dial 5s / Read 3s,Redis 半死不活 // (进程在但不响应)时会让每个请求白等这几秒,表现为整站变慢而无报错。 func PingRedis(addr, password string) error { ctx, cancel := context.WithTimeout(context.Background(), RedisPingTimeout) defer cancel() rdb := redis.NewClient(&redis.Options{ Addr: addr, Password: password, // DB 1 与 route.go 里 session 用的库保持一致:探活要探真正会用到的那一个, // 否则「DB 0 能用、DB 1 被 ACL 禁掉」这种配置错误探不出来。 DB: 1, DialTimeout: 2 * time.Second, ReadTimeout: 2 * time.Second, WriteTimeout: 2 * time.Second, }) defer func() { _ = rdb.Close() }() return rdb.Ping(ctx).Err() }