github.com/kelleygo/clashcore@v1.0.2/component/slowdown/slowdown.go (about) 1 package slowdown 2 3 import ( 4 "context" 5 "sync/atomic" 6 "time" 7 ) 8 9 type SlowDown struct { 10 errTimes atomic.Int64 11 backoff Backoff 12 } 13 14 func (s *SlowDown) Wait(ctx context.Context) (err error) { 15 timer := time.NewTimer(s.backoff.Duration()) 16 defer timer.Stop() 17 select { 18 case <-timer.C: 19 case <-ctx.Done(): 20 err = ctx.Err() 21 } 22 return 23 } 24 25 func New() *SlowDown { 26 return &SlowDown{ 27 backoff: Backoff{ 28 Min: 10 * time.Millisecond, 29 Max: 1 * time.Second, 30 Factor: 2, 31 Jitter: true, 32 }, 33 } 34 } 35 36 func Do[T any](s *SlowDown, ctx context.Context, fn func() (T, error)) (t T, err error) { 37 if s.errTimes.Load() > 10 { 38 err = s.Wait(ctx) 39 if err != nil { 40 return 41 } 42 } 43 t, err = fn() 44 if err != nil { 45 s.errTimes.Add(1) 46 return 47 } 48 s.errTimes.Store(0) 49 s.backoff.Reset() 50 return 51 }