fix: auto retry in exchangeWithoutCache

This commit is contained in:
gVisor bot 2022-11-19 08:51:00 +08:00
parent 538743555e
commit 5fd2771740

View File

@ -187,12 +187,16 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e
func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
q := m.Question[0] q := m.Question[0]
ch := r.group.DoChan(q.String(), func() (result any, err error) { retryNum := 0
retryMax := 3
fn := func() (result any, err error) {
ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) // reset timeout in singleflight ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) // reset timeout in singleflight
defer cancel() defer cancel()
defer func() { defer func() {
if err != nil { if err != nil {
result = retryNum
retryNum++
return return
} }
@ -210,7 +214,9 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M
return r.batchExchange(ctx, matched, m) return r.batchExchange(ctx, matched, m)
} }
return r.batchExchange(ctx, r.main, m) return r.batchExchange(ctx, r.main, m)
}) }
ch := r.group.DoChan(q.String(), fn)
var result singleflight.Result var result singleflight.Result
@ -219,13 +225,24 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M
break break
case <-ctx.Done(): case <-ctx.Done():
select { select {
case result = <-ch: case result = <-ch: // maybe ctxDone and chFinish in same time, get DoChan's result as much as possible
break break
default:
go func() { // start a retrying monitor in background
result := <-ch
ret, err, shared := result.Val, result.Err, result.Shared
if err != nil && !shared && ret.(int) < retryMax { // retry
r.group.DoChan(q.String(), fn)
} }
}()
return nil, ctx.Err() return nil, ctx.Err()
} }
}
ret, err, shared := result.Val, result.Err, result.Shared ret, err, shared := result.Val, result.Err, result.Shared
if err != nil && !shared && ret.(int) < retryMax { // retry
r.group.DoChan(q.String(), fn)
}
if err == nil { if err == nil {
msg = ret.(*D.Msg) msg = ret.(*D.Msg)