refactor: 重构失败主动健康检测

This commit is contained in:
Skyxim 2022-05-17 21:15:14 +08:00
parent f4d9384603
commit fa9e27c5e4
2 changed files with 53 additions and 32 deletions

View File

@ -19,8 +19,10 @@ type GroupBase struct {
providers []provider.ProxyProvider providers []provider.ProxyProvider
versions sync.Map // map[string]uint versions sync.Map // map[string]uint
proxies sync.Map // map[string][]C.Proxy proxies sync.Map // map[string][]C.Proxy
failedTimes *atomic.Int32 failedTestMux sync.Mutex
failedTime *atomic.Int64 failedTimes int
failedTime time.Time
failedTesting *atomic.Bool
} }
type GroupBaseOption struct { type GroupBaseOption struct {
@ -38,8 +40,7 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase {
Base: outbound.NewBase(opt.BaseOption), Base: outbound.NewBase(opt.BaseOption),
filter: filter, filter: filter,
providers: opt.providers, providers: opt.providers,
failedTimes: atomic.NewInt32(-1), failedTesting: atomic.NewBool(false),
failedTime: atomic.NewInt64(-1),
} }
} }
@ -105,29 +106,45 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
} }
func (gb *GroupBase) onDialFailed() { func (gb *GroupBase) onDialFailed() {
if gb.failedTime.Load() == -1 { if gb.failedTesting.Load() {
log.Warnln("%s first failed", gb.Name()) return
now := time.Now().UnixMilli()
gb.failedTime.Store(now)
gb.failedTimes.Store(1)
} else {
if gb.failedTime.Load()-time.Now().UnixMilli() > gb.failedIntervalTime() {
gb.failedTimes.Store(-1)
gb.failedTime.Store(-1)
} else {
failedCount := gb.failedTimes.Inc()
log.Warnln("%s failed count: %d", gb.Name(), failedCount)
if failedCount >= gb.maxFailedTimes() {
log.Warnln("because %s failed multiple times, active health check", gb.Name())
for _, proxyProvider := range gb.providers {
go proxyProvider.HealthCheck()
} }
gb.failedTimes.Store(-1) go func() {
gb.failedTime.Store(-1) gb.failedTestMux.Lock()
} defer func() {
gb.failedTestMux.Unlock()
}()
gb.failedTimes++
if gb.failedTimes == 1 {
log.Warnln("%s first failed", gb.Name())
gb.failedTime = time.Now()
} else {
if time.Since(gb.failedTime) > gb.failedTimeoutInterval() {
return
}
log.Warnln("%s failed count: %d", gb.Name(), gb.failedTimes)
if gb.failedTimes >= gb.maxFailedTimes() {
gb.failedTesting.Store(true)
log.Warnln("because %s failed multiple times, active health check", gb.Name())
wg := sync.WaitGroup{}
for _, proxyProvider := range gb.providers {
wg.Add(1)
proxyProvider := proxyProvider
go func() {
defer wg.Done()
proxyProvider.HealthCheck()
}()
}
wg.Wait()
gb.failedTesting.Store(false)
gb.failedTimes = 0
} }
} }
}()
} }
func (gb *GroupBase) failedIntervalTime() int64 { func (gb *GroupBase) failedIntervalTime() int64 {
@ -135,10 +152,15 @@ func (gb *GroupBase) failedIntervalTime() int64 {
} }
func (gb *GroupBase) onDialSuccess() { func (gb *GroupBase) onDialSuccess() {
gb.failedTimes.Store(-1) if !gb.failedTesting.Load() {
gb.failedTime.Store(-1) gb.failedTimes = 0
}
} }
func (gb *GroupBase) maxFailedTimes() int32 { func (gb *GroupBase) maxFailedTimes() int {
return 5 return 5
} }
func (gb *GroupBase) failedTimeoutInterval() time.Duration {
return 5 * time.Second
}

View File

@ -37,8 +37,7 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ..
c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...) c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil { if err == nil {
c.AppendToChains(u) c.AppendToChains(u)
u.failedTimes.Store(-1) u.onDialSuccess()
u.failedTime.Store(-1)
} else { } else {
u.onDialFailed() u.onDialFailed()
} }