87 lines
3.0 KiB
Go
87 lines
3.0 KiB
Go
package dispatch
|
|
|
|
// 熔断状态机。
|
|
//
|
|
// 状态转移逻辑为纯函数;计数与快照的原子存取由适配层(Redis Lua)负责。
|
|
// 适配层在 ReportOutcome 后读取窗口失败数,调用本文件的转移函数得到新快照并写回
|
|
//(写回本身用 Lua CAS 保证原子)。
|
|
//
|
|
// CLOSED → OPEN:滑动窗口内失败 ≥ failThreshold,或 CHANNEL_FATAL 一次直达
|
|
// OPEN → HALF_OPEN:冷却期满(惰性判定)
|
|
// HALF_OPEN → CLOSED:探测成功(rampFactor 开始爬坡)
|
|
// HALF_OPEN → OPEN:探测失败,冷却翻倍(上限封顶)
|
|
|
|
// BreakerSnapshot 熔断器快照(与 Redis hash 字段一一对应)。
|
|
type BreakerSnapshot struct {
|
|
State BreakerState
|
|
OpenedAtMs int64 // 进入 OPEN 的时间戳(毫秒)
|
|
CooldownMs int64 // 当前冷却时长(指数递增)
|
|
FailWindowCount int // 滑动窗口内失败数(由 Lua 维护,此处只读)
|
|
}
|
|
|
|
// EffectiveBreakerState 惰性判定当前有效状态:OPEN 且冷却期满 → HALF_OPEN。
|
|
// 只做读侧判定,不修改快照(HALF_OPEN 的探测放行由 StatePort.TryProbeToken 原子控制)。
|
|
func EffectiveBreakerState(s BreakerSnapshot, nowMs int64) BreakerState {
|
|
if s.State == BreakerOpen && nowMs-s.OpenedAtMs >= s.CooldownMs {
|
|
return BreakerHalfOpen
|
|
}
|
|
return s.State
|
|
}
|
|
|
|
// BreakerOnFailure 失败事件转移。fatal 表示 CHANNEL_FATAL 类错误(一次直达熔断)。
|
|
func BreakerOnFailure(s BreakerSnapshot, fatal bool, nowMs int64, p BreakerPolicy) BreakerSnapshot {
|
|
switch EffectiveBreakerState(s, nowMs) {
|
|
case BreakerHalfOpen:
|
|
// 探测失败:回 OPEN,冷却翻倍
|
|
s.State = BreakerOpen
|
|
s.OpenedAtMs = nowMs
|
|
s.CooldownMs = nextCooldownMs(s.CooldownMs, p)
|
|
return s
|
|
|
|
case BreakerOpen:
|
|
// 已在熔断中(未到冷却期),不重复转移
|
|
return s
|
|
|
|
default: // CLOSED
|
|
if fatal || s.FailWindowCount >= p.FailThreshold {
|
|
s.State = BreakerOpen
|
|
s.OpenedAtMs = nowMs
|
|
if s.CooldownMs <= 0 {
|
|
s.CooldownMs = int64(p.CooldownSeconds) * 1000
|
|
}
|
|
return s
|
|
}
|
|
return s
|
|
}
|
|
}
|
|
|
|
// BreakerOnSuccess 成功事件转移:HALF_OPEN 探测成功 → CLOSED,冷却复位。
|
|
func BreakerOnSuccess(s BreakerSnapshot, nowMs int64) BreakerSnapshot {
|
|
if EffectiveBreakerState(s, nowMs) == BreakerHalfOpen || s.State == BreakerClosed {
|
|
s.State = BreakerClosed
|
|
s.OpenedAtMs = 0
|
|
s.CooldownMs = 0
|
|
s.FailWindowCount = 0
|
|
}
|
|
return s
|
|
}
|
|
|
|
// ShouldAutoDisable OPEN 持续超过 autoDisableAfter → 落库禁用 + 清绑定 + 告警(适配层执行)。
|
|
func ShouldAutoDisable(s BreakerSnapshot, nowMs int64, p BreakerPolicy) bool {
|
|
return s.State == BreakerOpen && nowMs-s.OpenedAtMs >= int64(p.AutoDisableAfterSeconds)*1000
|
|
}
|
|
|
|
// nextCooldownMs 冷却指数递增,封顶 cooldownMax。
|
|
func nextCooldownMs(cur int64, p BreakerPolicy) int64 {
|
|
base := int64(p.CooldownSeconds) * 1000
|
|
maxMs := int64(p.CooldownMaxSeconds) * 1000
|
|
if cur <= 0 {
|
|
return base
|
|
}
|
|
next := cur * 2
|
|
if next > maxMs {
|
|
return maxMs
|
|
}
|
|
return next
|
|
}
|