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 &registry.ServiceEvent{
   122  			Action:  remoting.EventTypeDel,
   123  			Service: url,
   124  		}
   125  	}
   126  	return &registry.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  }