dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/xds/ewatcher/ewatcher.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package ewatcher 19 20 import ( 21 "fmt" 22 "strconv" 23 "sync" 24 ) 25 26 import ( 27 "github.com/dubbogo/gost/log/logger" 28 ) 29 30 import ( 31 "dubbo.apache.org/dubbo-go/v3/common" 32 "dubbo.apache.org/dubbo-go/v3/common/constant" 33 "dubbo.apache.org/dubbo-go/v3/registry" 34 "dubbo.apache.org/dubbo-go/v3/remoting" 35 xdsCommon "dubbo.apache.org/dubbo-go/v3/remoting/xds/common" 36 "dubbo.apache.org/dubbo-go/v3/xds/client/resource" 37 ) 38 39 // endPointWatcherCtx is endpoint watching context 40 type endPointWatcherCtx struct { 41 clusterName string 42 interfaceName string 43 hostAddr string 44 45 cancel func() 46 /* 47 hostAddrListenerMap[hostAddr][serviceUniqueKey] -> registry.NotifyListener 48 stores all directory listener, which receives events and refresh invokers 49 */ 50 hostAddrListenerMap map[string]map[string]registry.NotifyListener 51 hostAddrListenerMapLock *sync.RWMutex 52 } 53 54 func NewEndpointWatcherCtxImpl( 55 clusterName, 56 hostAddr, 57 interfaceName string, 58 hostAddrListenerMapLock *sync.RWMutex, 59 hostAddrListenerMap map[string]map[string]registry.NotifyListener) EWatcher { 60 return &endPointWatcherCtx{ 61 clusterName: clusterName, 62 hostAddr: hostAddr, 63 interfaceName: interfaceName, 64 hostAddrListenerMapLock: hostAddrListenerMapLock, 65 hostAddrListenerMap: hostAddrListenerMap, 66 } 67 } 68 69 func (watcher *endPointWatcherCtx) SetCancelFunction(cancel func()) { 70 watcher.cancel = cancel 71 } 72 73 // Handle handles endpoint update event and send to directory to refresh invoker 74 func (watcher *endPointWatcherCtx) Handle(update resource.EndpointsUpdate, err error) { 75 for _, v := range update.Localities { 76 for _, e := range v.Endpoints { 77 event := generateRegistryEvent(watcher.clusterName, e, watcher.interfaceName) 78 watcher.hostAddrListenerMapLock.RLock() 79 for _, l := range watcher.hostAddrListenerMap[watcher.hostAddr] { 80 // notify all listeners listening this hostAddr 81 l.Notify(event) 82 } 83 watcher.hostAddrListenerMapLock.RUnlock() 84 } 85 } 86 } 87 88 // Destroy call cancel and send event to listener to remove related invokers of current deleated cluster 89 func (watcher *endPointWatcherCtx) Destroy() { 90 if watcher.cancel != nil { 91 watcher.cancel() 92 } 93 /* 94 directory would identify this by EndpointHealthStatusUnhealthy and Location == "*" and none empty clusterID 95 and delete related invokers 96 */ 97 event := generateRegistryEvent(watcher.clusterName, resource.Endpoint{ 98 HealthStatus: resource.EndpointHealthStatusUnhealthy, 99 Address: constant.MeshAnyAddrMatcher, // Destroy all endpoint of this cluster 100 }, watcher.interfaceName) 101 watcher.hostAddrListenerMapLock.RLock() 102 for _, l := range watcher.hostAddrListenerMap[watcher.hostAddr] { 103 // notify all listeners listening this hostAddr 104 l.Notify(event) 105 } 106 watcher.hostAddrListenerMapLock.RUnlock() 107 } 108 109 func generateRegistryEvent(clusterID string, endpoint resource.Endpoint, interfaceName string) *registry.ServiceEvent { 110 // todo now only support triple protocol 111 url, _ := common.NewURL(fmt.Sprintf("tri://%s/%s", endpoint.Address, interfaceName)) 112 logger.Infof("[XDS Registry] Get Update event from pilot: interfaceName = %s, addr = %s, healthy = %d\n", 113 interfaceName, endpoint.Address, endpoint.HealthStatus) 114 cluster := xdsCommon.NewCluster(clusterID) 115 // todo const MeshSubsetKey 116 url.AddParam(constant.MeshSubsetKey, cluster.Subset) 117 url.AddParam(constant.MeshClusterIDKey, clusterID) 118 url.AddParam(constant.MeshHostAddrKey, cluster.Addr.String()) 119 url.AddParam(constant.EndPointWeight, strconv.Itoa(int(endpoint.Weight))) 120 if endpoint.HealthStatus == resource.EndpointHealthStatusUnhealthy { 121 return ®istry.ServiceEvent{ 122 Action: remoting.EventTypeDel, 123 Service: url, 124 } 125 } 126 return ®istry.ServiceEvent{ 127 Action: remoting.EventTypeUpdate, 128 Service: url, 129 } 130 } 131 132 type EWatcher interface { 133 Destroy() 134 Handle(update resource.EndpointsUpdate, err error) 135 SetCancelFunction(cancel func()) 136 }