7
7
"time"
8
8
9
9
"github.com/metacubex/mihomo/common/utils"
10
+ "github.com/metacubex/mihomo/component/slowdown"
10
11
types "github.com/metacubex/mihomo/constant/provider"
11
12
"github.com/metacubex/mihomo/log"
12
13
@@ -29,6 +30,7 @@ type Fetcher[V any] struct {
29
30
onUpdate func (V )
30
31
watcher * fswatch.Watcher
31
32
loadBufMutex sync.Mutex
33
+ backoff slowdown.Backoff
32
34
}
33
35
34
36
func (f * Fetcher [V ]) Name () string {
@@ -83,6 +85,7 @@ func (f *Fetcher[V]) Initial() (V, error) {
83
85
func (f * Fetcher [V ]) Update () (V , bool , error ) {
84
86
buf , hash , err := f .vehicle .Read (f .ctx , f .hash )
85
87
if err != nil {
88
+ f .backoff .AddAttempt () // add a failed attempt to backoff
86
89
return lo .Empty [V ](), false , err
87
90
}
88
91
return f .loadBuf (buf , hash , f .vehicle .Type () != types .File )
@@ -111,8 +114,10 @@ func (f *Fetcher[V]) loadBuf(buf []byte, hash utils.HashType, updateFile bool) (
111
114
112
115
contents , err := f .parser (buf )
113
116
if err != nil {
117
+ f .backoff .AddAttempt () // add a failed attempt to backoff
114
118
return lo .Empty [V ](), false , err
115
119
}
120
+ f .backoff .Reset () // no error, reset backoff
116
121
117
122
if updateFile {
118
123
if err = f .vehicle .Write (buf ); err != nil {
@@ -147,14 +152,25 @@ func (f *Fetcher[V]) pullLoop(forceUpdate bool) {
147
152
log .Warnln ("[Provider] %s not updated for a long time, force refresh" , f .Name ())
148
153
f .updateWithLog ()
149
154
}
155
+ if attempt := f .backoff .Attempt (); attempt > 0 { // f.Update() was failed, decrease the interval from backoff to achieve fast retry
156
+ if duration := f .backoff .ForAttempt (attempt ); duration < initialInterval {
157
+ initialInterval = duration
158
+ }
159
+ }
150
160
151
161
timer := time .NewTimer (initialInterval )
152
162
defer timer .Stop ()
153
163
for {
154
164
select {
155
165
case <- timer .C :
156
- timer .Reset (f .interval )
157
166
f .updateWithLog ()
167
+ interval := f .interval
168
+ if attempt := f .backoff .Attempt (); attempt > 0 { // f.Update() was failed, decrease the interval from backoff to achieve fast retry
169
+ if duration := f .backoff .ForAttempt (attempt ); duration < interval {
170
+ interval = duration
171
+ }
172
+ }
173
+ timer .Reset (interval )
158
174
case <- f .ctx .Done ():
159
175
return
160
176
}
@@ -212,5 +228,11 @@ func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicl
212
228
parser : parser ,
213
229
onUpdate : onUpdate ,
214
230
interval : interval ,
231
+ backoff : slowdown.Backoff {
232
+ Factor : 2 ,
233
+ Jitter : false ,
234
+ Min : time .Second ,
235
+ Max : interval ,
236
+ },
215
237
}
216
238
}
0 commit comments