diff --git a/common/picker/picker.go b/common/picker/picker.go index 0c846cb9..9f38aede 100644 --- a/common/picker/picker.go +++ b/common/picker/picker.go @@ -15,8 +15,10 @@ type Picker struct { wg sync.WaitGroup - once sync.Once - result interface{} + once sync.Once + errOnce sync.Once + result interface{} + err error } func newPicker(ctx context.Context, cancel func()) *Picker { @@ -49,6 +51,11 @@ func (p *Picker) Wait() interface{} { return p.result } +// Error return the first error (if all success return nil) +func (p *Picker) Error() error { + return p.err +} + // Go calls the given function in a new goroutine. // The first call to return a nil error cancels the group; its result will be returned by Wait. func (p *Picker) Go(f func() (interface{}, error)) { @@ -64,6 +71,10 @@ func (p *Picker) Go(f func() (interface{}, error)) { p.cancel() } }) + } else { + p.errOnce.Do(func() { + p.err = err + }) } }() } diff --git a/common/picker/picker_test.go b/common/picker/picker_test.go index 8f0ba958..82122d7f 100644 --- a/common/picker/picker_test.go +++ b/common/picker/picker_test.go @@ -36,4 +36,5 @@ func TestPicker_Timeout(t *testing.T) { number := picker.Wait() assert.Nil(t, number) + assert.NotNil(t, picker.Error()) } diff --git a/dns/resolver.go b/dns/resolver.go index f1f51a98..eec7d412 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "errors" + "fmt" "math/rand" "net" "strings" @@ -182,7 +183,11 @@ func (r *Resolver) batchExchange(clients []dnsClient, m *D.Msg) (msg *D.Msg, err elm := fast.Wait() if elm == nil { - return nil, errors.New("All DNS requests failed") + err := errors.New("All DNS requests failed") + if fErr := fast.Error(); fErr != nil { + err = fmt.Errorf("%w, first error: %s", err, fErr.Error()) + } + return nil, err } msg = elm.(*D.Msg)