feat(ops): 健康检查端点,并把上传超时与服务端读超时对齐
1) /healthz 与 /readyz
改动前站内唯一的「探活」手段是 curl /,而首页只渲染模板、不查数据库:
DB 挂了首页照样 200(漏报),Redis 挂了首页又可能 500(误报)。
监控、CDN 源站健康检查、滚动重启的摘流判定都没有可靠依据。
→ /healthz 永远 200,刻意不碰任何依赖:进程活着 ≠ 能对外服务,
把 DB 检查塞进存活探针会导致数据库抖动时进程被反复重启,对恢复毫无帮助;
→ /readyz 查 DB(2s 超时),失败 503;响应体只回组件状态,
绝不回错误详情 —— 这是公开端点,DB 报错常带库名/主机名/账号。
实测:停掉 PostgreSQL 后 /healthz 仍 200、/readyz 503,恢复后 200。
2) ReadTimeout 30s → 120s
站内允许单图 8MB、请求体上限 12MB。30s 传完 8MB 需要 ≥273 KB/s 上行,
而手机 4G 上行常在 1–2 Mbps(125–250 KB/s)—— 一张 8MB 图必然超时,
且用户已写好的正文会一起丢(POST 失败不回填)。120s 对应约 68 KB/s,
偏远地区 3G 也能过。
放宽它不会让 slowloris 重新可行:那类攻击卡在「发不完 header」,
由 10s 的 ReadHeaderTimeout 拦住,ReadTimeout 只影响读完 header 之后传 body 的时长。
This commit is contained in:
@@ -15,6 +15,25 @@ import (
|
||||
"github.com/tamakyi/TamaBox/internal/conf"
|
||||
)
|
||||
|
||||
// handle 保存 Init 建立的连接,供「不需要具体 store」的场景使用(如就绪探针)。
|
||||
// 与下面那些业务 store 的包级变量区分开:那些是接口,这个是连接本身。
|
||||
var handle *gorm.DB
|
||||
|
||||
// Ping 检查数据库连接是否可用。供 /readyz 就绪探针调用。
|
||||
//
|
||||
// 为什么需要它:原来的「探活」只能 curl /,而首页只渲染模板、不碰数据库 ——
|
||||
// DB 挂了首页照样 200,反过来 Redis 挂了首页又可能 500。于是探针既会漏报也会误报。
|
||||
func Ping(ctx context.Context) error {
|
||||
if handle == nil {
|
||||
return errors.New("database not initialized")
|
||||
}
|
||||
sqlDB, err := handle.DB()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get sql.DB")
|
||||
}
|
||||
return sqlDB.PingContext(ctx)
|
||||
}
|
||||
|
||||
var AllTables = []interface{}{
|
||||
&User{}, &Question{}, &FollowUp{}, &CensorLog{}, &UploadImage{}, &UploadImageQuestion{},
|
||||
&Conversation{}, &Message{}, &MessageImage{}, &UserBlock{},
|
||||
@@ -48,6 +67,7 @@ func Init(typ, dsn string) (*gorm.DB, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "connect to database")
|
||||
}
|
||||
handle = db
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user