gitee.com/h79/goutils@v1.22.10/thrift/client/resolver_conn_wrapper.go (about) 1 package client 2 3 import ( 4 "gitee.com/h79/goutils/common/system" 5 "gitee.com/h79/goutils/thrift/resolver" 6 "sync" 7 "time" 8 ) 9 10 type ccResolverWrapper struct { 11 cc *Client 12 resolverMu sync.Mutex 13 resolver resolver.Resolver 14 curState resolver.State 15 done *system.Event 16 pollingMu sync.Mutex 17 polling chan struct{} 18 } 19 20 // newCCResolverWrapper uses the resolver.Builder to build a Resolver and 21 // returns a ccResolverWrapper object which wraps the newly built resolver. 22 func newCCResolverWrapper(cc *Client, rb resolver.Builder) (*ccResolverWrapper, error) { 23 ccr := &ccResolverWrapper{ 24 cc: cc, 25 done: system.NewEvent(), 26 } 27 28 var err error 29 // We need to hold the lock here while we assign to the ccr.resolver field 30 // to guard against a data race caused by the following code path, 31 // rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up 32 // accessing ccr.resolver which is being assigned here. 33 ccr.resolverMu.Lock() 34 defer ccr.resolverMu.Unlock() 35 ccr.resolver, err = rb.Build(cc.parsedTarget, ccr) 36 if err != nil { 37 return nil, err 38 } 39 return ccr, nil 40 } 41 42 func (ccr *ccResolverWrapper) resolveNow() { 43 ccr.resolverMu.Lock() 44 if !ccr.done.HasFired() { 45 ccr.resolver.ResolveNow() 46 } 47 ccr.resolverMu.Unlock() 48 } 49 50 func (ccr *ccResolverWrapper) close() { 51 ccr.resolverMu.Lock() 52 ccr.resolver.Close() 53 ccr.done.Fire() 54 ccr.resolverMu.Unlock() 55 } 56 57 func (ccr *ccResolverWrapper) stopPolling() { 58 // stop polling 59 if ccr.polling != nil { 60 close(ccr.polling) 61 ccr.polling = nil 62 } 63 } 64 65 // poll begins or ends asynchronous polling of the resolver based on whether 66 // err is ErrBadResolverState. 67 func (ccr *ccResolverWrapper) poll(err error) { 68 ccr.pollingMu.Lock() 69 defer ccr.pollingMu.Unlock() 70 if err != nil { 71 ccr.stopPolling() 72 return 73 } 74 if ccr.polling != nil { 75 // already polling 76 return 77 } 78 p := make(chan struct{}) 79 ccr.polling = p 80 system.ChildRunning(func() { 81 for i := 0; ; i++ { 82 ccr.resolveNow() 83 t := time.NewTimer(time.Second * time.Duration(2+i*5)) 84 select { 85 case <-p: 86 t.Stop() 87 return 88 case <-ccr.done.Done(): 89 // Resolver has been closed. 90 t.Stop() 91 return 92 case <-t.C: 93 select { 94 case <-p: 95 return 96 default: 97 } 98 // Timer expired; re-resolve. 99 case <-system.Closed(): 100 return 101 } 102 } 103 }) 104 } 105 106 func (ccr *ccResolverWrapper) UpdateState(s resolver.State) { 107 if ccr.done.HasFired() { 108 return 109 } 110 ccr.curState = s 111 ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil)) 112 } 113 114 func (ccr *ccResolverWrapper) ReportError(err error) { 115 if ccr.done.HasFired() { 116 return 117 } 118 ccr.poll(ccr.cc.updateResolverState(resolver.State{}, err)) 119 } 120 121 func (ccr *ccResolverWrapper) NewAddress(adders []resolver.Address) { 122 if ccr.done.HasFired() { 123 return 124 } 125 126 ccr.curState.Addresses = adders 127 ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil)) 128 }