mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 11:36:36 +08:00
0aff87c69d
优化
120 lines
2.5 KiB
Go
120 lines
2.5 KiB
Go
package cloud115
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ThrottleManager 全局限流/熔断管理器,用于控制 115 API 访问频率与被风控时的全局静默冷却。
|
|
type ThrottleManager struct {
|
|
sync.RWMutex
|
|
isThrottled bool
|
|
throttleStartTime time.Time
|
|
throttleNotify chan struct{}
|
|
throttleDuration time.Duration
|
|
}
|
|
|
|
var (
|
|
globalThrottleManager *ThrottleManager
|
|
throttleOnce sync.Once
|
|
)
|
|
|
|
// GetGlobalThrottleManager 获取全局限流管理器单例。
|
|
func GetGlobalThrottleManager() *ThrottleManager {
|
|
throttleOnce.Do(func() {
|
|
globalThrottleManager = NewThrottleManager(60 * time.Second)
|
|
})
|
|
return globalThrottleManager
|
|
}
|
|
|
|
// NewThrottleManager 创建限流管理器。
|
|
func NewThrottleManager(duration time.Duration) *ThrottleManager {
|
|
if duration <= 0 {
|
|
duration = 60 * time.Second
|
|
}
|
|
return &ThrottleManager{
|
|
isThrottled: false,
|
|
throttleNotify: make(chan struct{}),
|
|
throttleDuration: duration,
|
|
}
|
|
}
|
|
|
|
// IsThrottled 检查是否处于限流冷却状态。
|
|
func (tm *ThrottleManager) IsThrottled() bool {
|
|
tm.RLock()
|
|
defer tm.RUnlock()
|
|
|
|
if !tm.isThrottled {
|
|
return false
|
|
}
|
|
if time.Since(tm.throttleStartTime) >= tm.throttleDuration {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// MarkThrottled 标记为限流状态,并启动恢复计时器。
|
|
func (tm *ThrottleManager) MarkThrottled() {
|
|
tm.Lock()
|
|
defer tm.Unlock()
|
|
|
|
if tm.isThrottled && time.Since(tm.throttleStartTime) < tm.throttleDuration {
|
|
return
|
|
}
|
|
|
|
tm.isThrottled = true
|
|
tm.throttleStartTime = time.Now()
|
|
|
|
go tm.startRecoveryTimer()
|
|
}
|
|
|
|
func (tm *ThrottleManager) startRecoveryTimer() {
|
|
time.Sleep(tm.throttleDuration)
|
|
|
|
tm.Lock()
|
|
defer tm.Unlock()
|
|
|
|
tm.isThrottled = false
|
|
|
|
select {
|
|
case tm.throttleNotify <- struct{}{}:
|
|
default:
|
|
}
|
|
}
|
|
|
|
// WaitThrottleRecovery 如果处于限流状态,挂起等待直到冷却恢复。
|
|
func (tm *ThrottleManager) WaitThrottleRecovery(ctx context.Context) error {
|
|
for {
|
|
if !tm.IsThrottled() {
|
|
return nil
|
|
}
|
|
|
|
ticker := time.NewTicker(200 * time.Millisecond)
|
|
select {
|
|
case <-ctx.Done():
|
|
ticker.Stop()
|
|
return ctx.Err()
|
|
case <-ticker.C:
|
|
ticker.Stop()
|
|
if !tm.IsThrottled() {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset 重置限流状态(主要用于单元测试)。
|
|
func (tm *ThrottleManager) Reset() {
|
|
tm.Lock()
|
|
defer tm.Unlock()
|
|
tm.isThrottled = false
|
|
}
|
|
|
|
// SetDuration 调整限流冷却时间(用于测试或动态配置)。
|
|
func (tm *ThrottleManager) SetDuration(d time.Duration) {
|
|
tm.Lock()
|
|
defer tm.Unlock()
|
|
tm.throttleDuration = d
|
|
}
|