dubbo.apache.org/dubbo-go/v3@v3.1.1/config/consumer_config.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 config
    19  
    20  import (
    21  	"fmt"
    22  	"strings"
    23  	"time"
    24  )
    25  
    26  import (
    27  	"github.com/creasty/defaults"
    28  
    29  	"github.com/dubbogo/gost/log/logger"
    30  
    31  	tripleConstant "github.com/dubbogo/triple/pkg/common/constant"
    32  )
    33  
    34  import (
    35  	"dubbo.apache.org/dubbo-go/v3/common"
    36  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    37  )
    38  
    39  const (
    40  	MaxWheelTimeSpan = 900e9 // 900s, 15 minute
    41  )
    42  
    43  // ConsumerConfig is Consumer default configuration
    44  type ConsumerConfig struct {
    45  	Filter                         string                      `yaml:"filter" json:"filter,omitempty" property:"filter"`
    46  	RegistryIDs                    []string                    `yaml:"registry-ids" json:"registry-ids,omitempty" property:"registry-ids"`
    47  	Protocol                       string                      `yaml:"protocol" json:"protocol,omitempty" property:"protocol"`
    48  	RequestTimeout                 string                      `default:"3s" yaml:"request-timeout" json:"request-timeout,omitempty" property:"request-timeout"`
    49  	ProxyFactory                   string                      `default:"default" yaml:"proxy" json:"proxy,omitempty" property:"proxy"`
    50  	Check                          bool                        `yaml:"check" json:"check,omitempty" property:"check"`
    51  	AdaptiveService                bool                        `default:"false" yaml:"adaptive-service" json:"adaptive-service" property:"adaptive-service"`
    52  	References                     map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
    53  	TracingKey                     string                      `yaml:"tracing-key" json:"tracing-key" property:"tracing-key"`
    54  	FilterConf                     interface{}                 `yaml:"filter-conf" json:"filter-conf,omitempty" property:"filter-conf"`
    55  	MaxWaitTimeForServiceDiscovery string                      `default:"3s" yaml:"max-wait-time-for-service-discovery" json:"max-wait-time-for-service-discovery,omitempty" property:"max-wait-time-for-service-discovery"`
    56  	MeshEnabled                    bool                        `yaml:"mesh-enabled" json:"mesh-enabled,omitempty" property:"mesh-enabled"`
    57  	rootConfig                     *RootConfig
    58  }
    59  
    60  // Prefix dubbo.consumer
    61  func (ConsumerConfig) Prefix() string {
    62  	return constant.ConsumerConfigPrefix
    63  }
    64  
    65  func (cc *ConsumerConfig) Init(rc *RootConfig) error {
    66  	if cc == nil {
    67  		return nil
    68  	}
    69  
    70  	buildDebugMsg := func() string {
    71  		if len(cc.References) == 0 {
    72  			return "empty"
    73  		}
    74  		consumerNames := make([]string, 0, len(cc.References))
    75  		for k := range cc.References {
    76  			consumerNames = append(consumerNames, k)
    77  		}
    78  		return strings.Join(consumerNames, ", ")
    79  	}
    80  	logger.Debugf("Registered consumer clients are %v", buildDebugMsg())
    81  
    82  	cc.RegistryIDs = translateIds(cc.RegistryIDs)
    83  	if len(cc.RegistryIDs) <= 0 {
    84  		cc.RegistryIDs = rc.getRegistryIds()
    85  	}
    86  	if cc.TracingKey == "" && len(rc.Tracing) > 0 {
    87  		for k := range rc.Tracing {
    88  			cc.TracingKey = k
    89  			break
    90  		}
    91  	}
    92  	for key, referenceConfig := range cc.References {
    93  		if referenceConfig.InterfaceName == "" {
    94  			reference := GetConsumerService(key)
    95  			// try to use interface name defined by pb
    96  			triplePBService, ok := reference.(common.TriplePBService)
    97  			if !ok {
    98  				logger.Errorf("Dubbo-go cannot get interface name with reference = %s."+
    99  					"Please run the command 'go install github.com/dubbogo/dubbogo-cli/cmd/protoc-gen-go-triple@latest' to get the latest "+
   100  					"protoc-gen-go-triple,  and then re-generate your pb file again by this tool."+
   101  					"If you are not using pb serialization, please set 'interfaceName' field in reference config to let dubbogo get the interface name.", key)
   102  				continue
   103  			} else {
   104  				// use interface name defined by pb
   105  				referenceConfig.InterfaceName = triplePBService.XXX_InterfaceName()
   106  			}
   107  		}
   108  		if err := referenceConfig.Init(rc); err != nil {
   109  			return err
   110  		}
   111  	}
   112  	if err := defaults.Set(cc); err != nil {
   113  		return err
   114  	}
   115  	if err := verify(cc); err != nil {
   116  		return err
   117  	}
   118  
   119  	cc.rootConfig = rc
   120  	return nil
   121  }
   122  
   123  func (cc *ConsumerConfig) Load() {
   124  	for registeredTypeName, refRPCService := range GetConsumerServiceMap() {
   125  		refConfig, ok := cc.References[registeredTypeName]
   126  		if !ok {
   127  			// not found configuration, now new a configuration with default.
   128  			refConfig = NewReferenceConfigBuilder().SetProtocol(tripleConstant.TRIPLE).Build()
   129  			triplePBService, ok := refRPCService.(common.TriplePBService)
   130  			if !ok {
   131  				logger.Errorf("Dubbo-go cannot get interface name with registeredTypeName = %s."+
   132  					"Please run the command 'go install github.com/dubbogo/dubbogo-cli/cmd/protoc-gen-go-triple@latest' to get the latest "+
   133  					"protoc-gen-go-triple,  and then re-generate your pb file again by this tool."+
   134  					"If you are not using pb serialization, please set 'interfaceName' field in reference config to let dubbogo get the interface name.", registeredTypeName)
   135  				continue
   136  			} else {
   137  				// use interface name defined by pb
   138  				refConfig.InterfaceName = triplePBService.XXX_InterfaceName()
   139  			}
   140  			if err := refConfig.Init(rootConfig); err != nil {
   141  				logger.Errorf(fmt.Sprintf("reference with registeredTypeName = %s init failed! err: %#v", registeredTypeName, err))
   142  				continue
   143  			}
   144  		}
   145  		refConfig.id = registeredTypeName
   146  		refConfig.Refer(refRPCService)
   147  		refConfig.Implement(refRPCService)
   148  	}
   149  
   150  	var maxWait int
   151  
   152  	if maxWaitDuration, err := time.ParseDuration(cc.MaxWaitTimeForServiceDiscovery); err != nil {
   153  		logger.Warnf("Invalid consumer max wait time for service discovery: %s, fallback to 3s", cc.MaxWaitTimeForServiceDiscovery)
   154  		maxWait = 3
   155  	} else {
   156  		maxWait = int(maxWaitDuration.Seconds())
   157  	}
   158  
   159  	// wait for invoker is available, if wait over default 3s, then panic
   160  	var count int
   161  	for {
   162  		checkok := true
   163  		for key, ref := range cc.References {
   164  			if (ref.Check != nil && *ref.Check && GetProviderService(key) == nil) ||
   165  				(ref.Check == nil && cc.Check && GetProviderService(key) == nil) ||
   166  				(ref.Check == nil && GetProviderService(key) == nil) { // default to true
   167  
   168  				if ref.invoker != nil && !ref.invoker.IsAvailable() {
   169  					checkok = false
   170  					count++
   171  					if count > maxWait {
   172  						errMsg := fmt.Sprintf("No provider available of the service %v.please check configuration.", ref.InterfaceName)
   173  						logger.Error(errMsg)
   174  						panic(errMsg)
   175  					}
   176  					time.Sleep(time.Second * 1)
   177  					break
   178  				}
   179  				if ref.invoker == nil {
   180  					logger.Warnf("The interface %s invoker not exist, may you should check your interface config.", ref.InterfaceName)
   181  				}
   182  			}
   183  		}
   184  		if checkok {
   185  			break
   186  		}
   187  	}
   188  }
   189  
   190  // SetConsumerConfig sets consumerConfig by @c
   191  func SetConsumerConfig(c ConsumerConfig) {
   192  	rootConfig.Consumer = &c
   193  }
   194  
   195  func newEmptyConsumerConfig() *ConsumerConfig {
   196  	newConsumerConfig := &ConsumerConfig{
   197  		References:     make(map[string]*ReferenceConfig, 8),
   198  		RequestTimeout: "3s",
   199  		Check:          true,
   200  	}
   201  	return newConsumerConfig
   202  }
   203  
   204  type ConsumerConfigBuilder struct {
   205  	consumerConfig *ConsumerConfig
   206  }
   207  
   208  func NewConsumerConfigBuilder() *ConsumerConfigBuilder {
   209  	return &ConsumerConfigBuilder{consumerConfig: newEmptyConsumerConfig()}
   210  }
   211  
   212  func (ccb *ConsumerConfigBuilder) SetFilter(filter string) *ConsumerConfigBuilder {
   213  	ccb.consumerConfig.Filter = filter
   214  	return ccb
   215  }
   216  
   217  func (ccb *ConsumerConfigBuilder) SetRegistryIDs(RegistryIDs ...string) *ConsumerConfigBuilder {
   218  	ccb.consumerConfig.RegistryIDs = RegistryIDs
   219  	return ccb
   220  }
   221  
   222  func (ccb *ConsumerConfigBuilder) SetRequestTimeout(requestTimeout string) *ConsumerConfigBuilder {
   223  	ccb.consumerConfig.RequestTimeout = requestTimeout
   224  	return ccb
   225  }
   226  
   227  func (ccb *ConsumerConfigBuilder) SetMaxWaitTimeForServiceDiscovery(maxWaitTimeForServiceDiscovery string) *ConsumerConfigBuilder {
   228  	ccb.consumerConfig.MaxWaitTimeForServiceDiscovery = maxWaitTimeForServiceDiscovery
   229  	return ccb
   230  }
   231  
   232  func (ccb *ConsumerConfigBuilder) SetProxyFactory(proxyFactory string) *ConsumerConfigBuilder {
   233  	ccb.consumerConfig.ProxyFactory = proxyFactory
   234  	return ccb
   235  }
   236  
   237  func (ccb *ConsumerConfigBuilder) SetCheck(check bool) *ConsumerConfigBuilder {
   238  	ccb.consumerConfig.Check = check
   239  	return ccb
   240  }
   241  
   242  func (ccb *ConsumerConfigBuilder) AddReference(referenceKey string, referenceConfig *ReferenceConfig) *ConsumerConfigBuilder {
   243  	ccb.consumerConfig.References[referenceKey] = referenceConfig
   244  	return ccb
   245  }
   246  
   247  func (ccb *ConsumerConfigBuilder) SetReferences(references map[string]*ReferenceConfig) *ConsumerConfigBuilder {
   248  	ccb.consumerConfig.References = references
   249  	return ccb
   250  }
   251  
   252  func (ccb *ConsumerConfigBuilder) SetFilterConf(filterConf interface{}) *ConsumerConfigBuilder {
   253  	ccb.consumerConfig.FilterConf = filterConf
   254  	return ccb
   255  }
   256  
   257  func (ccb *ConsumerConfigBuilder) SetMeshEnabled(meshEnabled bool) *ConsumerConfigBuilder {
   258  	ccb.consumerConfig.MeshEnabled = meshEnabled
   259  	return ccb
   260  }
   261  
   262  func (ccb *ConsumerConfigBuilder) SetRootConfig(rootConfig *RootConfig) *ConsumerConfigBuilder {
   263  	ccb.consumerConfig.rootConfig = rootConfig
   264  	return ccb
   265  }
   266  
   267  func (ccb *ConsumerConfigBuilder) Build() *ConsumerConfig {
   268  	return ccb.consumerConfig
   269  }
   270  
   271  // DynamicUpdateProperties dynamically update properties.
   272  func (cc *ConsumerConfig) DynamicUpdateProperties(newConsumerConfig *ConsumerConfig) {
   273  	if newConsumerConfig != nil && newConsumerConfig.RequestTimeout != cc.RequestTimeout {
   274  		cc.RequestTimeout = newConsumerConfig.RequestTimeout
   275  		logger.Infof("ConsumerConfig's RequestTimeout was dynamically updated, new value:%v", cc.RequestTimeout)
   276  	}
   277  }