gcli2api / internal /server /degrade.go
a3216's picture
chore: 同步到上游 1.12.0-panel + 凭证同步/独立启动器/保活
6d60378 verified
Raw History Blame Contribute Delete
1.99 kB
package server
import (
"sync"
"time"
)
// degradeGate 降级状态机:passthrough 模式下请求被上游内容策略拦截时,
// 切换到 Degraded 中性提示词直到次日 00:00 CST 重置。
//
// 定位:误报处理(与 internal/upstream/sanitize.go 同哲学)——内容拦截多为
// system 来源的指纹误报,换最小中性提示词即可绕开;不是对抗框架。
//
// 状态机:进程内存、重启清零(可接受:重启极少触发,且 custom 模式根本
// 不进降级路径)。降级期内的请求直达 Degraded,不再先撞 400。
type degradeGate struct {
mu sync.Mutex
until time.Time
}
// Active 当前是否处于降级期(now < until)。
func (g *degradeGate) Active() bool {
g.mu.Lock()
defer g.mu.Unlock()
return time.Now().Before(g.until)
}
// Trigger 触发降级,直到次日 00:00 CST(Asia/Shanghai)。
// 已在降级期内则不续期(保持最早触发点的 00:00 重置语义)。
func (g *degradeGate) Trigger() {
g.mu.Lock()
defer g.mu.Unlock()
if !time.Now().Before(g.until) {
// 已过期/未触发 → 设新的 until;未过期则保持原 until(不续期)。
g.until = nextMidnightCST(time.Now())
}
}
// nextMidnightCST 返回 now 之后最近的 Asia/Shanghai 00:00 时刻(纯函数,方便单测)。
//
// 边界语义:
// - 23:59 → 次日 00:00(几秒后)
// - 00:00 → 次日 00:00(刚过 00:00,下个零点是次日)
//
// 用固定 +08:00 偏移计算,避免依赖系统时区配置(容器/宿主机时区不确定)。
func nextMidnightCST(now time.Time) time.Time {
cst := time.FixedZone("CST", 8*60*60)
// 把 now 转到 CST 视角取当天 00:00,再加一天;若该 00:00 <= now 则再加一天。
y, m, d := now.In(cst).Date()
midnight := time.Date(y, m, d, 0, 0, 0, 0, cst)
for !midnight.After(now) {
midnight = midnight.Add(24 * time.Hour)
}
return midnight
}