diff --git a/.asf.yaml b/.asf.yaml index 8d84e695a5..db175df5d6 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -1,5 +1,5 @@ -notifications: - commits: commits@dubbo.apache.org - issues: notifications@dubbo.apache.org - pullrequests: notifications@dubbo.apache.org - jira_options: link label link label +notifications: + commits: commits@dubbo.apache.org + issues: notifications@dubbo.apache.org + pullrequests: notifications@dubbo.apache.org + jira_options: link label link label diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 3e01441f7e..81e13ae9b1 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,19 +1,19 @@ ---- -name: Bug Report -about: Report a bug -labels: kind/bug - ---- - - - - -**What happened**: - -**What you expected to happen**: - -**How to reproduce it (as minimally and precisely as possible)**: - -**Anything else we need to know?**: +--- +name: Bug Report +about: Report a bug +labels: kind/bug + +--- + + + + +**What happened**: + +**What you expected to happen**: + +**How to reproduce it (as minimally and precisely as possible)**: + +**Anything else we need to know?**: diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md index 6d1a6d99f9..fd3ac94dab 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.md +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -1,11 +1,11 @@ ---- -name: Enhancement Request -about: Suggest an enhancement -labels: kind/feature - ---- - - -**What would you like to be added**: - +--- +name: Enhancement Request +about: Suggest an enhancement +labels: kind/feature + +--- + + +**What would you like to be added**: + **Why is this needed**: \ No newline at end of file diff --git a/common/constant/key.go b/common/constant/key.go index 1cdd258834..7f371c4b96 100644 --- a/common/constant/key.go +++ b/common/constant/key.go @@ -313,11 +313,12 @@ const ( const ( SUBSCRIBED_SERVICE_NAMES_KEY = "subscribed-services" PROVIDER_BY = "provided-by" - EXPORTED_SERVICES_REVISION_PROPERTY_NAME = "dubbo.exported-services.revision" + EXPORTED_SERVICES_REVISION_PROPERTY_NAME = "dubbo.metadata.revision" SUBSCRIBED_SERVICES_REVISION_PROPERTY_NAME = "dubbo.subscribed-services.revision" SERVICE_INSTANCE_SELECTOR = "service-instance-selector" METADATA_STORAGE_TYPE_PROPERTY_NAME = "dubbo.metadata.storage-type" DEFAULT_METADATA_STORAGE_TYPE = "local" + REMOTE_METADATA_STORAGE_TYPE = "remote" SERVICE_INSTANCE_ENDPOINTS = "dubbo.endpoints" METADATA_SERVICE_PREFIX = "dubbo.metadata-service." METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME = METADATA_SERVICE_PREFIX + "url-params" diff --git a/common/extension/metadata_remote.go b/common/extension/metadata_remote.go new file mode 100644 index 0000000000..878e26be19 --- /dev/null +++ b/common/extension/metadata_remote.go @@ -0,0 +1,33 @@ +package extension + +import ( + "fmt" +) + +import ( + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/metadata/service/remote" +) + +type remoteMetadataServiceCreator func() (remote.RemoteMetadataService, error) + +var ( + creator remoteMetadataServiceCreator +) + +// SetRemoteMetadataService will store the remote metadata service +func SetRemoteMetadataService(creatorFunc remoteMetadataServiceCreator) { + creator = creatorFunc +} + +// GetRemoteMetadataServiceFactory will create a MetadataService instance +func GetRemoteMetadataService() (remote.RemoteMetadataService, error) { + if creator != nil { + return creator() + } + return nil, perrors.New(fmt.Sprintf("could not find the metadata service creator for metadataType: remote, please check whether you have imported relative packages, \n" + + "remote - github.com/apache/dubbo-go/metadata/remote/impl")) +} diff --git a/common/extension/metadata_service.go b/common/extension/metadata_service.go index 08ddbc333e..a2d498f9cb 100644 --- a/common/extension/metadata_service.go +++ b/common/extension/metadata_service.go @@ -26,42 +26,29 @@ import ( ) import ( - "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/metadata/service" ) +type localMetadataServiceCreator func() (service.MetadataService, error) + var ( - // there will be two types: local or remote - metadataServiceInsMap = make(map[string]func() (service.MetadataService, error), 2) - // remoteMetadataService - remoteMetadataService service.MetadataService + localMetadataServiceInsMap = make(map[string]localMetadataServiceCreator, 2) ) -// SetMetadataService will store the msType => creator pair -func SetMetadataService(msType string, creator func() (service.MetadataService, error)) { - metadataServiceInsMap[msType] = creator -} - -// GetMetadataService will create a MetadataService instance -func GetMetadataService(msType string) (service.MetadataService, error) { - if creator, ok := metadataServiceInsMap[msType]; ok { - return creator() - } - return nil, perrors.New(fmt.Sprintf("could not find the metadata service creator for metadataType: %s, please check whether you have imported relative packages, \n"+ - "local - github.com/apache/dubbo-go/metadata/service/inmemory, \n"+ - "remote - github.com/apache/dubbo-go/metadata/service/remote", msType)) +// SetLocalMetadataService will store the msType => creator pair +func SetLocalMetadataService(key string, creator localMetadataServiceCreator) { + localMetadataServiceInsMap[key] = creator } -// GetRemoteMetadataService will get a RemoteMetadataService instance -func GetRemoteMetadataService() (service.MetadataService, error) { - if remoteMetadataService != nil { - return remoteMetadataService, nil +// GetMetadataService will create a inmemory MetadataService instance +func GetLocalMetadataService(key string) (service.MetadataService, error) { + if key == "" { + key = constant.DEFAULT_KEY } - if creator, ok := metadataServiceInsMap["remote"]; ok { - var err error - remoteMetadataService, err = creator() - return remoteMetadataService, err + if creator, ok := localMetadataServiceInsMap[key]; ok { + return creator() } - logger.Warn("could not find the metadata service creator for metadataType: remote") - return nil, perrors.New(fmt.Sprintf("could not find the metadata service creator for metadataType: remote")) + return nil, perrors.New(fmt.Sprintf("could not find the metadata service creator for metadataType: local, please check whether you have imported relative packages, \n" + + "local - github.com/apache/dubbo-go/metadata/service/inmemory, ")) } diff --git a/common/extension/metadata_service_proxy_factory.go b/common/extension/metadata_service_proxy_factory.go index 3e05c2257f..3f10e33dc7 100644 --- a/common/extension/metadata_service_proxy_factory.go +++ b/common/extension/metadata_service_proxy_factory.go @@ -22,6 +22,7 @@ import ( ) import ( + "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/metadata/service" ) @@ -37,10 +38,12 @@ func SetMetadataServiceProxyFactory(name string, creator MetadataServiceProxyFac // GetMetadataServiceProxyFactory will create an instance. // it will panic if the factory with name not found func GetMetadataServiceProxyFactory(name string) service.MetadataServiceProxyFactory { + if name == "" { + name = constant.DEFAULT_KEY + } if f, ok := metadataServiceProxyFactoryMap[name]; ok { return f() } panic(fmt.Sprintf("could not find the metadata service factory creator for name: %s, please check whether you have imported relative packages, \n"+ - "local - github.com/apache/dubbo-go/metadata/service/inmemory, \n"+ - "remote - github.com/apache/dubbo-go/metadata/service/remote", name)) + "local - github.com/apache/dubbo-go/metadata/service/inmemory, \n", name)) } diff --git a/common/metadata_info.go b/common/metadata_info.go new file mode 100644 index 0000000000..36736562b4 --- /dev/null +++ b/common/metadata_info.go @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "hash/crc32" + "net/url" + "sort" + "strings" +) + +import ( + gxset "github.com/dubbogo/gost/container/set" + "go.uber.org/atomic" +) + +import ( + "github.com/apache/dubbo-go/common/constant" +) + +var IncludeKeys = gxset.NewSet( + constant.APPLICATION_KEY, + constant.GROUP_KEY, + constant.TIMESTAMP_KEY, + constant.SERIALIZATION_KEY, + constant.CLUSTER_KEY, + constant.LOADBALANCE_KEY, + constant.PATH_KEY, + constant.TIMEOUT_KEY, + constant.TOKEN_KEY, + constant.VERSION_KEY, + constant.WARMUP_KEY, + constant.WEIGHT_KEY, + constant.RELEASE_KEY) + +// MetadataInfo the metadata information of instance +type MetadataInfo struct { + App string `json:"app,omitempty"` + Revision string `json:"revision,omitempty"` + Services map[string]*ServiceInfo `json:"services,omitempty"` + + Reported *atomic.Bool `json:"-"` +} + +// nolint +func NewMetadataInfWithApp(app string) *MetadataInfo { + return NewMetadataInfo(app, "", make(map[string]*ServiceInfo)) +} + +// nolint +func NewMetadataInfo(app string, revision string, services map[string]*ServiceInfo) *MetadataInfo { + return &MetadataInfo{ + App: app, + Revision: revision, + Services: services, + Reported: atomic.NewBool(false), + } +} + +// nolint +func (mi *MetadataInfo) JavaClassName() string { + return "org.apache.dubbo.metadata.MetadataInfo" +} + +// CalAndGetRevision is different from Dubbo because golang doesn't support overload +// so that we should use interface + method name as identifier and ignore the method params +// in my opinion, it's enough because Dubbo actually ignore the Url params. +// please refer org.apache.dubbo.common.URL#toParameterString(java.lang.String...) +func (mi *MetadataInfo) CalAndGetRevision() string { + if mi.Revision != "" && mi.Reported.Load() { + return mi.Revision + } + if len(mi.Services) == 0 { + return "0" + } + candidates := make([]string, 8) + + for _, s := range mi.Services { + sk := s.ServiceKey + ms := s.Url.Methods + if len(ms) == 0 { + candidates = append(candidates, sk) + } else { + for _, m := range ms { + // methods are part of candidates + candidates = append(candidates, sk+constant.KEY_SEPARATOR+m) + } + } + + // append Url params if we need it + } + sort.Strings(candidates) + + // it's nearly impossible to be overflow + res := uint64(0) + for _, c := range candidates { + res += uint64(crc32.ChecksumIEEE([]byte(c))) + } + mi.Revision = fmt.Sprint(res) + return mi.Revision + +} + +// nolint +func (mi *MetadataInfo) HasReported() bool { + return mi.Reported.Load() +} + +// nolint +func (mi *MetadataInfo) MarkReported() { + mi.Reported.CAS(false, true) +} + +// nolint +func (mi *MetadataInfo) AddService(service *ServiceInfo) { + if service == nil { + return + } + mi.Services[service.GetMatchKey()] = service +} + +// nolint +func (mi *MetadataInfo) RemoveService(service *ServiceInfo) { + if service == nil { + return + } + delete(mi.Services, service.MatchKey) +} + +// ServiceInfo the information of service +type ServiceInfo struct { + Name string `json:"name,omitempty"` + Group string `json:"group,omitempty"` + Version string `json:"version,omitempty"` + Protocol string `json:"protocol,omitempty"` + Path string `json:"path,omitempty"` + Params map[string]string `json:"params,omitempty"` + + ServiceKey string `json:"-"` + MatchKey string `json:"-"` + Url *URL `json:"-"` +} + +// nolint +func NewServiceInfoWithUrl(url *URL) *ServiceInfo { + service := NewServiceInfo(url.Service(), url.Group(), url.Version(), url.Protocol, url.Path, nil) + service.Url = url + // TODO includeKeys load dynamic + p := make(map[string]string, 8) + for _, keyInter := range IncludeKeys.Values() { + key := keyInter.(string) + value := url.GetParam(key, "") + if len(value) != 0 { + p[key] = value + } + for _, method := range url.Methods { + value = url.GetMethodParam(method, key, "") + if len(value) != 0 { + p[method+"."+key] = value + } + } + } + service.Params = p + return service +} + +// nolint +func NewServiceInfo(name, group, version, protocol, path string, params map[string]string) *ServiceInfo { + serviceKey := ServiceKey(name, group, version) + matchKey := MatchKey(serviceKey, protocol) + return &ServiceInfo{ + Name: name, + Group: group, + Version: version, + Protocol: protocol, + Path: path, + Params: params, + ServiceKey: serviceKey, + MatchKey: matchKey, + } +} + +// nolint +func (si *ServiceInfo) JavaClassName() string { + return "org.apache.dubbo.metadata.MetadataInfo$ServiceInfo" +} + +// nolint +func (si *ServiceInfo) GetMethods() []string { + if si.Params[constant.METHODS_KEY] != "" { + s := si.Params[constant.METHODS_KEY] + return strings.Split(s, ",") + } + methods := make([]string, 8) + for k, _ := range si.Params { + ms := strings.Index(k, ".") + if ms > 0 { + methods = append(methods, k[0:ms]) + } + } + return methods +} + +// nolint +func (si *ServiceInfo) GetParams() url.Values { + v := url.Values{} + for k, p := range si.Params { + ms := strings.Index(k, ".") + if ms > 0 { + v.Set("methods."+k, p) + } else { + v.Set(k, p) + } + } + return v +} + +// nolint +func (si *ServiceInfo) GetMatchKey() string { + if si.MatchKey != "" { + return si.MatchKey + } + serviceKey := si.GetServiceKey() + si.MatchKey = MatchKey(serviceKey, si.Protocol) + return si.MatchKey +} + +// nolint +func (si *ServiceInfo) GetServiceKey() string { + if si.ServiceKey != "" { + return si.ServiceKey + } + si.ServiceKey = ServiceKey(si.Name, si.Group, si.Version) + return si.ServiceKey +} diff --git a/common/rpc_service.go b/common/rpc_service.go index 30d72c1420..bd716edc5a 100644 --- a/common/rpc_service.go +++ b/common/rpc_service.go @@ -236,7 +236,7 @@ func (sm *serviceMap) Register(interfaceName, protocol, group, version string, r // UnRegister cancels a service by @interfaceName, @protocol and @serviceId func (sm *serviceMap) UnRegister(interfaceName, protocol, serviceKey string) error { if protocol == "" || serviceKey == "" { - return perrors.New("protocol or serviceKey is nil") + return perrors.New("protocol or ServiceKey is nil") } var ( diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go index ce861b75e7..32e5254874 100644 --- a/common/rpc_service_test.go +++ b/common/rpc_service_test.go @@ -126,7 +126,7 @@ func TestServiceMapUnRegister(t *testing.T) { assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService"))) err = ServiceMap.UnRegister("", "", ServiceKey("TestService", "", "v1")) - assert.EqualError(t, err, "protocol or serviceKey is nil") + assert.EqualError(t, err, "protocol or ServiceKey is nil") err = ServiceMap.UnRegister("", "protocol", ServiceKey("TestService", "", "v1")) assert.EqualError(t, err, "no services for protocol") diff --git a/common/url.go b/common/url.go index 6863230c93..cc62bfee88 100644 --- a/common/url.go +++ b/common/url.go @@ -64,7 +64,7 @@ var ( DubboNodes = [...]string{"consumers", "configurators", "routers", "providers"} // DubboRole Dubbo service role DubboRole = [...]string{"consumer", "", "routers", "provider"} - // CompareURLEqualFunc compare two url is equal + // CompareURLEqualFunc compare two Url is equal compareURLEqualFunc CompareURLEqualFunc ) @@ -104,7 +104,7 @@ type noCopy struct{} func (*noCopy) Lock() {} func (*noCopy) Unlock() {} -// URL thread-safe. but this url should not be copied. +// URL thread-safe. but this Url should not be copied. // we fail to define this struct to be immutable object. // but, those method which will update the URL, including SetParam, SetParams // are only allowed to be invoked in creating URL instance @@ -125,81 +125,81 @@ type URL struct { SubURL *URL } -// Option accepts url +// Option accepts Url // Option will define a function of handling URL type Option func(*URL) -// WithUsername sets username for url +// WithUsername sets username for Url func WithUsername(username string) Option { return func(url *URL) { url.Username = username } } -// WithPassword sets password for url +// WithPassword sets password for Url func WithPassword(pwd string) Option { return func(url *URL) { url.Password = pwd } } -// WithMethods sets methods for url +// WithMethods sets methods for Url func WithMethods(methods []string) Option { return func(url *URL) { url.Methods = methods } } -// WithParams sets params for url +// WithParams sets params for Url func WithParams(params url.Values) Option { return func(url *URL) { url.params = params } } -// WithParamsValue sets params field for url +// WithParamsValue sets params field for Url func WithParamsValue(key, val string) Option { return func(url *URL) { url.SetParam(key, val) } } -// WithProtocol sets protocol for url +// WithProtocol sets protocol for Url func WithProtocol(proto string) Option { return func(url *URL) { url.Protocol = proto } } -// WithIp sets ip for url +// WithIp sets ip for Url func WithIp(ip string) Option { return func(url *URL) { url.Ip = ip } } -// WithPort sets port for url +// WithPort sets port for Url func WithPort(port string) Option { return func(url *URL) { url.Port = port } } -// WithPath sets path for url +// WithPath sets path for Url func WithPath(path string) Option { return func(url *URL) { url.Path = "/" + strings.TrimPrefix(path, "/") } } -// WithLocation sets location for url +// WithLocation sets location for Url func WithLocation(location string) Option { return func(url *URL) { url.Location = location } } -// WithToken sets token for url +// WithToken sets token for Url func WithToken(token string) Option { return func(url *URL) { if len(token) > 0 { @@ -217,7 +217,7 @@ func WithToken(token string) Option { } } -// NewURLWithOptions will create a new url with options +// NewURLWithOptions will create a new Url with options func NewURLWithOptions(opts ...Option) *URL { newURL := &URL{} for _, opt := range opts { @@ -227,7 +227,7 @@ func NewURLWithOptions(opts ...Option) *URL { return newURL } -// NewURL will create a new url +// NewURL will create a new Url // the urlString should not be empty func NewURL(urlString string, opts ...Option) (*URL, error) { s := URL{baseUrl: baseUrl{}} @@ -237,7 +237,7 @@ func NewURL(urlString string, opts ...Option) (*URL, error) { rawUrlString, err := url.QueryUnescape(urlString) if err != nil { - return &s, perrors.Errorf("url.QueryUnescape(%s), error{%v}", urlString, err) + return &s, perrors.Errorf("Url.QueryUnescape(%s), error{%v}", urlString, err) } // rawUrlString = "//" + rawUrlString @@ -251,12 +251,12 @@ func NewURL(urlString string, opts ...Option) (*URL, error) { serviceUrl, urlParseErr := url.Parse(rawUrlString) if urlParseErr != nil { - return &s, perrors.Errorf("url.Parse(url string{%s}), error{%v}", rawUrlString, err) + return &s, perrors.Errorf("Url.Parse(Url string{%s}), error{%v}", rawUrlString, err) } s.params, err = url.ParseQuery(serviceUrl.RawQuery) if err != nil { - return &s, perrors.Errorf("url.ParseQuery(raw url string{%s}), error{%v}", serviceUrl.RawQuery, err) + return &s, perrors.Errorf("Url.ParseQuery(raw Url string{%s}), error{%v}", serviceUrl.RawQuery, err) } s.PrimitiveURL = urlString @@ -268,7 +268,7 @@ func NewURL(urlString string, opts ...Option) (*URL, error) { if strings.Contains(s.Location, ":") { s.Ip, s.Port, err = net.SplitHostPort(s.Location) if err != nil { - return &s, perrors.Errorf("net.SplitHostPort(url.Host{%s}), error{%v}", s.Location, err) + return &s, perrors.Errorf("net.SplitHostPort(Url.Host{%s}), error{%v}", s.Location, err) } } for _, opt := range opts { @@ -277,7 +277,21 @@ func NewURL(urlString string, opts ...Option) (*URL, error) { return &s, nil } -// URLEqual judge @url and @c is equal or not. +func MatchKey(serviceKey string, protocol string) string { + return serviceKey + ":" + protocol +} + +// Group get group +func (c *URL) Group() string { + return c.GetParam(constant.GROUP_KEY, "") +} + +// Version get group +func (c *URL) Version() string { + return c.GetParam(constant.VERSION_KEY, "") +} + +// URLEqual judge @Url and @c is equal or not. func (c *URL) URLEqual(url *URL) bool { tmpC := c.Clone() tmpC.Ip = "" @@ -303,7 +317,7 @@ func (c *URL) URLEqual(url *URL) bool { return false } - // 2. if url contains enabled key, should be true, or * + // 2. if Url contains enabled key, should be true, or * if tmpUrl.GetParam(constant.ENABLED_KEY, "true") != "true" && tmpUrl.GetParam(constant.ENABLED_KEY, "") != constant.ANY_VALUE { return false } @@ -415,7 +429,7 @@ func (c *URL) Service() string { return service } else if c.SubURL != nil { service = c.SubURL.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")) - if service != "" { // if url.path is "" then return suburl's path, special for registry url + if service != "" { // if Url.path is "" then return suburl's path, special for registry Url return service } } @@ -442,8 +456,8 @@ func (c *URL) AddParamAvoidNil(key string, value string) { c.params.Add(key, value) } -// SetParam will put the key-value pair into url -// usually it should only be invoked when you want to initialized an url +// SetParam will put the key-value pair into Url +// usually it should only be invoked when you want to initialized an Url func (c *URL) SetParam(key string, value string) { c.paramsLock.Lock() defer c.paramsLock.Unlock() @@ -453,7 +467,7 @@ func (c *URL) SetParam(key string, value string) { c.params.Set(key, value) } -// DelParam will delete the given key from the url +// DelParam will delete the given key from the Url func (c *URL) DelParam(key string) { c.paramsLock.Lock() defer c.paramsLock.Unlock() @@ -463,7 +477,7 @@ func (c *URL) DelParam(key string) { } // ReplaceParams will replace the URL.params -// usually it should only be invoked when you want to modify an url, such as MergeURL +// usually it should only be invoked when you want to modify an Url, such as MergeURL func (c *URL) ReplaceParams(param url.Values) { c.paramsLock.Lock() defer c.paramsLock.Unlock() @@ -607,7 +621,7 @@ func (c *URL) GetMethodParamBool(method string, key string, d bool) bool { return r } -// SetParams will put all key-value pair into url. +// SetParams will put all key-value pair into Url. // 1. if there already has same key, the value will be override // 2. it's not thread safe // 3. think twice when you want to invoke this method @@ -658,10 +672,10 @@ func (c *URL) ToMap() map[string]string { } // configuration > reference config >service config -// in this function we should merge the reference local url config into the service url from registry. +// in this function we should merge the reference local Url config into the service Url from registry. // TODO configuration merge, in the future , the configuration center's config should merge too. -// MergeURL will merge those two url +// MergeURL will merge those two Url // the result is based on serviceUrl, and the key which si only contained in referenceUrl // will be added into result. // for example, if serviceUrl contains params (a1->v1, b1->v2) and referenceUrl contains params(a2->v3, b1 -> v4) @@ -669,11 +683,11 @@ func (c *URL) ToMap() map[string]string { // You should notice that the value of b1 is v2, not v4. // due to URL is not thread-safe, so this method is not thread-safe func MergeURL(serviceUrl *URL, referenceUrl *URL) *URL { - // After Clone, it is a new url that there is no thread safe issue. + // After Clone, it is a new Url that there is no thread safe issue. mergedUrl := serviceUrl.Clone() params := mergedUrl.GetParams() // iterator the referenceUrl if serviceUrl not have the key ,merge in - // referenceUrl usually will not changed. so change RangeParams to GetParams to avoid the string value copy. + // referenceUrl usually will not changed. so change RangeParams to GetParams to avoid the string value copy.// Group get group for key, value := range referenceUrl.GetParams() { if v := mergedUrl.GetParam(key, ""); len(v) == 0 { if len(value) > 0 { @@ -702,7 +716,7 @@ func MergeURL(serviceUrl *URL, referenceUrl *URL) *URL { return mergedUrl } -// Clone will copy the url +// Clone will copy the Url func (c *URL) Clone() *URL { newURL := &URL{} if err := copier.Copy(newURL, c); err != nil { @@ -747,7 +761,7 @@ func (c *URL) Compare(comp cm.Comparator) int { } } -// Copy url based on the reserved parameter's keys. +// Copy Url based on the reserved parameter's keys. func (c *URL) CloneWithParams(reserveParams []string) *URL { params := url.Values{} for _, reserveParam := range reserveParams { diff --git a/common/yaml/testdata/config.yml b/common/yaml/testdata/config.yml index b5c2ca8ad1..a56c842529 100644 --- a/common/yaml/testdata/config.yml +++ b/common/yaml/testdata/config.yml @@ -1,7 +1,7 @@ - -intTest: 11 -booleanTest: false -strTest: "strTest" - -child: + +intTest: 11 +booleanTest: false +strTest: "strTest" + +child: strTest: "childStrTest" \ No newline at end of file diff --git a/config/config_loader.go b/config/config_loader.go index 44a0601034..7f82b78dc1 100644 --- a/config/config_loader.go +++ b/config/config_loader.go @@ -29,6 +29,7 @@ import ( ) import ( + hessian "github.com/apache/dubbo-go-hessian2" perrors "github.com/pkg/errors" ) @@ -298,6 +299,10 @@ func registerServiceInstance() { panic(err) } } + // todo publish metadata to remote + if remoteMetadataServiceImpl, err := extension.GetRemoteMetadataService(); err == nil { + remoteMetadataServiceImpl.PublishMetadata(GetApplicationConfig().Name) + } } // nolint @@ -331,24 +336,19 @@ func createInstance(url *common.URL) (registry.ServiceInstance, error) { // selectMetadataServiceExportedURL get already be exported url func selectMetadataServiceExportedURL() *common.URL { var selectedUrl *common.URL - metaDataService, err := extension.GetMetadataService(GetApplicationConfig().MetadataType) + metaDataService, err := extension.GetLocalMetadataService("") if err != nil { logger.Warn(err) return nil } - list, err := metaDataService.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) + urlList, err := metaDataService.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) if err != nil { panic(err) } - if len(list) == 0 { + if len(urlList) == 0 { return nil } - for _, urlStr := range list { - url, err := common.NewURL(urlStr.(string)) - if err != nil { - logger.Errorf("url format error {%v}", url) - continue - } + for _, url := range urlList { selectedUrl = url // rest first if url.Protocol == "rest" { @@ -373,6 +373,10 @@ func Load() { } func LoadWithOptions(options ...LoaderInitOption) { + // register metadata info and service info + hessian.RegisterPOJO(&common.MetadataInfo{}) + hessian.RegisterPOJO(&common.ServiceInfo{}) + for _, option := range options { option.init() } diff --git a/config/config_loader_test.go b/config/config_loader_test.go index 4a3de5aad2..a1a495005b 100644 --- a/config/config_loader_test.go +++ b/config/config_loader_test.go @@ -86,7 +86,7 @@ func TestLoad(t *testing.T) { extension.SetProxyFactory("default", proxy_factory.NewDefaultProxyFactory) GetApplicationConfig().MetadataType = "mock" var mm *mockMetadataService - extension.SetMetadataService("mock", func() (metadataService service.MetadataService, err error) { + extension.SetLocalMetadataService("mock", func() (metadataService service.MetadataService, err error) { if mm == nil { mm = &mockMetadataService{ exportedServiceURLs: new(sync.Map), @@ -126,7 +126,7 @@ func TestLoadWithSingleReg(t *testing.T) { extension.SetProxyFactory("default", proxy_factory.NewDefaultProxyFactory) var mm *mockMetadataService GetApplicationConfig().MetadataType = "mock" - extension.SetMetadataService("mock", func() (metadataService service.MetadataService, err error) { + extension.SetLocalMetadataService("mock", func() (metadataService service.MetadataService, err error) { if mm == nil { mm = &mockMetadataService{ exportedServiceURLs: new(sync.Map), @@ -165,7 +165,7 @@ func TestWithNoRegLoad(t *testing.T) { extension.SetProxyFactory("default", proxy_factory.NewDefaultProxyFactory) var mm *mockMetadataService GetApplicationConfig().MetadataType = "mock" - extension.SetMetadataService("mock", func() (metadataService service.MetadataService, err error) { + extension.SetLocalMetadataService("mock", func() (metadataService service.MetadataService, err error) { if mm == nil { mm = &mockMetadataService{ exportedServiceURLs: new(sync.Map), @@ -373,6 +373,26 @@ type mockMetadataService struct { lock *sync.RWMutex } +func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]*common.URL, error) { + panic("implement me") +} + +func (m *mockMetadataService) GetMetadataInfo(revision string) (*common.MetadataInfo, error) { + panic("implement me") +} + +func (m *mockMetadataService) GetExportedServiceURLs() []*common.URL { + panic("implement me") +} + +func (m *mockMetadataService) GetMetadataServiceURL() *common.URL { + panic("implement me") +} + +func (m *mockMetadataService) SetMetadataServiceURL(url *common.URL) { + panic("implement me") +} + func (m *mockMetadataService) Reference() string { panic("implement me") } @@ -401,10 +421,6 @@ func (m *mockMetadataService) PublishServiceDefinition(*common.URL) error { return nil } -func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]interface{}, error) { - return ConvertURLArrToIntfArr(m.getAllService(m.exportedServiceURLs)), nil -} - func (m *mockMetadataService) MethodMapper() map[string]string { panic("implement me") } @@ -553,7 +569,7 @@ func (m *mockServiceDiscovery) GetRequestInstances([]string, int, int) map[strin panic("implement me") } -func (m *mockServiceDiscovery) AddListener(*registry.ServiceInstancesChangedListener) error { +func (m *mockServiceDiscovery) AddListener(registry.ServiceInstancesChangedListener) error { panic("implement me") } diff --git a/config/instance/metadata_report_test.go b/config/instance/metadata_report_test.go index 7d4a93ad13..6420fe095a 100644 --- a/config/instance/metadata_report_test.go +++ b/config/instance/metadata_report_test.go @@ -50,6 +50,14 @@ func (m *mockMetadataReportFactory) CreateMetadataReport(*common.URL) report.Met type mockMetadataReport struct{} +func (m mockMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + panic("implement me") +} + +func (m mockMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + panic("implement me") +} + func (m mockMetadataReport) StoreProviderMetadata(*identifier.MetadataIdentifier, string) error { panic("implement me") } diff --git a/config/reference_config.go b/config/reference_config.go index a2a163441a..4493055d1a 100644 --- a/config/reference_config.go +++ b/config/reference_config.go @@ -262,8 +262,8 @@ func (c *ReferenceConfig) GetInvoker() protocol.Invoker { } func publishConsumerDefinition(url *common.URL) { - if remoteMetadataService, err := extension.GetRemoteMetadataService(); err == nil && remoteMetadataService != nil { - remoteMetadataService.PublishServiceDefinition(url) + if remoteMetadataServiceImpl, err := extension.GetRemoteMetadataService(); err == nil && remoteMetadataServiceImpl != nil { + remoteMetadataServiceImpl.PublishServiceDefinition(url) } } diff --git a/config/reference_config_test.go b/config/reference_config_test.go index 433d584c92..826e404ac5 100644 --- a/config/reference_config_test.go +++ b/config/reference_config_test.go @@ -342,7 +342,7 @@ func (*mockRegistryProtocol) Refer(url *common.URL) protocol.Invoker { func (*mockRegistryProtocol) Export(invoker protocol.Invoker) protocol.Exporter { registryURL := getRegistryURL(invoker) if registryURL.Protocol == "service-discovery" { - metaDataService, err := extension.GetMetadataService(GetApplicationConfig().MetadataType) + metaDataService, err := extension.GetLocalMetadataService("") if err != nil { panic(err) } diff --git a/config/service_config.go b/config/service_config.go index d73190c48f..53672b6a9f 100644 --- a/config/service_config.go +++ b/config/service_config.go @@ -227,6 +227,13 @@ func (c *ServiceConfig) Export() error { c.exporters = append(c.exporters, exporter) } } else { + if ivkURL.GetParam(constant.INTERFACE_KEY, "") == constant.METADATA_SERVICE_NAME { + ms, err := extension.GetLocalMetadataService("") + if err != nil { + return err + } + ms.SetMetadataServiceURL(ivkURL) + } invoker := proxyFactory.GetInvoker(ivkURL) exporter := extension.GetProtocol(protocolwrapper.FILTER).Export(invoker) if exporter == nil { @@ -349,8 +356,9 @@ func (c *ServiceConfig) GetExportedUrls() []*common.URL { } func publishServiceDefinition(url *common.URL) { - if remoteMetadataService, err := extension.GetRemoteMetadataService(); err == nil && remoteMetadataService != nil { - remoteMetadataService.PublishServiceDefinition(url) + if remoteMetadataServiceImpl, err := extension.GetRemoteMetadataService(); err == nil && remoteMetadataServiceImpl != nil { + remoteMetadataServiceImpl.PublishServiceDefinition(url) + } } diff --git a/config/testdata/consumer_config.properties b/config/testdata/consumer_config.properties index da9fe4f3b3..e370813b37 100644 --- a/config/testdata/consumer_config.properties +++ b/config/testdata/consumer_config.properties @@ -1,52 +1,52 @@ -filter= -request_timeout=100ms -connect_timeout=100ms -check=true -application.organization=ikurento.com -application.name=BDTService -application.module=dubbogo user-info client -application.version=0.0.1 -application.owner=ZX -application.environment=dev -registries.hangzhouzk.protocol=zookeeper -registries.hangzhouzk.timeout=3s -registries.hangzhouzk.address=127.0.0.1:2181 -registries.hangzhouzk.username= -registries.hangzhouzk.password= -registries.shanghaizk.protocol=zookeeper -registries.shanghaizk.timeout=3s -registries.shanghaizk.address=127.0.0.1:2182 -registries.shanghaizk.username= -registries.shanghaizk.password= -references.UserProvider.registry=hangzhouzk,shanghaizk -references.UserProvider.filter= -references.UserProvider.version=1.0 -references.UserProvider.group=as -references.UserProvider.interface=com.ikurento.user.UserProvider -references.UserProvider.url=dubbo://127.0.0.1:20000/UserProvider -references.UserProvider.cluster=failover -references.UserProvider.methods[0].name=GetUser -references.UserProvider.methods[0].retries=3 -references.UserProvider.params.serviceid=soa.com.ikurento.user.UserProvider -references.UserProvider.params.forks=5 -protocol_conf.dubbo.reconnect_interval=0 -protocol_conf.dubbo.connection_number=2 -protocol_conf.dubbo.heartbeat_period=5s -protocol_conf.dubbo.session_timeout=20s -protocol_conf.dubbo.pool_size=64 -protocol_conf.dubbo.pool_ttl=600 -protocol_conf.dubbo.gr_pool_size=1200 -protocol_conf.dubbo.queue_len=64 -protocol_conf.dubbo.queue_number=60 -protocol_conf.dubbo.getty_session_param.compress_encoding=false -protocol_conf.dubbo.getty_session_param.tcp_no_delay=true -protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true -protocol_conf.dubbo.getty_session_param.keep_alive_period=120s -protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144 -protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536 -protocol_conf.dubbo.getty_session_param.pkg_wq_size=512 -protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s -protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s -protocol_conf.dubbo.getty_session_param.wait_timeout=1s -protocol_conf.dubbo.getty_session_param.max_msg_len=1024 +filter= +request_timeout=100ms +connect_timeout=100ms +check=true +application.organization=ikurento.com +application.name=BDTService +application.module=dubbogo user-info client +application.version=0.0.1 +application.owner=ZX +application.environment=dev +registries.hangzhouzk.protocol=zookeeper +registries.hangzhouzk.timeout=3s +registries.hangzhouzk.address=127.0.0.1:2181 +registries.hangzhouzk.username= +registries.hangzhouzk.password= +registries.shanghaizk.protocol=zookeeper +registries.shanghaizk.timeout=3s +registries.shanghaizk.address=127.0.0.1:2182 +registries.shanghaizk.username= +registries.shanghaizk.password= +references.UserProvider.registry=hangzhouzk,shanghaizk +references.UserProvider.filter= +references.UserProvider.version=1.0 +references.UserProvider.group=as +references.UserProvider.interface=com.ikurento.user.UserProvider +references.UserProvider.url=dubbo://127.0.0.1:20000/UserProvider +references.UserProvider.cluster=failover +references.UserProvider.methods[0].name=GetUser +references.UserProvider.methods[0].retries=3 +references.UserProvider.params.serviceid=soa.com.ikurento.user.UserProvider +references.UserProvider.params.forks=5 +protocol_conf.dubbo.reconnect_interval=0 +protocol_conf.dubbo.connection_number=2 +protocol_conf.dubbo.heartbeat_period=5s +protocol_conf.dubbo.session_timeout=20s +protocol_conf.dubbo.pool_size=64 +protocol_conf.dubbo.pool_ttl=600 +protocol_conf.dubbo.gr_pool_size=1200 +protocol_conf.dubbo.queue_len=64 +protocol_conf.dubbo.queue_number=60 +protocol_conf.dubbo.getty_session_param.compress_encoding=false +protocol_conf.dubbo.getty_session_param.tcp_no_delay=true +protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true +protocol_conf.dubbo.getty_session_param.keep_alive_period=120s +protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144 +protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536 +protocol_conf.dubbo.getty_session_param.pkg_wq_size=512 +protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s +protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s +protocol_conf.dubbo.getty_session_param.wait_timeout=1s +protocol_conf.dubbo.getty_session_param.max_msg_len=1024 protocol_conf.dubbo.getty_session_param.session_name=client \ No newline at end of file diff --git a/config/testdata/consumer_config_with_configcenter.yml b/config/testdata/consumer_config_with_configcenter.yml index ebe56fa93f..89869dcff5 100644 --- a/config/testdata/consumer_config_with_configcenter.yml +++ b/config/testdata/consumer_config_with_configcenter.yml @@ -1,44 +1,44 @@ -# dubbo client yaml configure file - -application: - name: "BDTService" -config_center: - protocol: "mock" - address: "127.0.0.1" -references: - "UserProvider": - registry: "hangzhouzk,shanghaizk" - filter: "" - protocol : "dubbo" - interface : "com.ikurento.user.UserProvider" - url: "dubbo://127.0.0.1:20000/UserProvider" - cluster: "failover" - methods : - - name: "GetUser" - retries: "3" - -shutdown_conf: - timeout: 60s - step_timeout: 10s - -protocol_conf: - dubbo: - reconnect_interval: 0 - connection_number: 2 - heartbeat_period: "5s" - session_timeout: "20s" - pool_size: 64 - pool_ttl: 600 - getty_session_param: - compress_encoding: false - tcp_no_delay: true - tcp_keep_alive: true - keep_alive_period: "120s" - tcp_r_buf_size: 262144 - tcp_w_buf_size: 65536 - pkg_wq_size: 512 - tcp_read_timeout: "1s" - tcp_write_timeout: "5s" - wait_timeout: "1s" - max_msg_len: 1024 - session_name: "client" +# dubbo client yaml configure file + +application: + name: "BDTService" +config_center: + protocol: "mock" + address: "127.0.0.1" +references: + "UserProvider": + registry: "hangzhouzk,shanghaizk" + filter: "" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + url: "dubbo://127.0.0.1:20000/UserProvider" + cluster: "failover" + methods : + - name: "GetUser" + retries: "3" + +shutdown_conf: + timeout: 60s + step_timeout: 10s + +protocol_conf: + dubbo: + reconnect_interval: 0 + connection_number: 2 + heartbeat_period: "5s" + session_timeout: "20s" + pool_size: 64 + pool_ttl: 600 + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 16498688 + session_name: "client" diff --git a/config/testdata/consumer_config_with_configcenter_apollo.yml b/config/testdata/consumer_config_with_configcenter_apollo.yml index 49b8fff595..71a8b8c9df 100644 --- a/config/testdata/consumer_config_with_configcenter_apollo.yml +++ b/config/testdata/consumer_config_with_configcenter_apollo.yml @@ -1,24 +1,24 @@ -# use apollo config center for fetch config file -# default config file namespace is dubbo.properties -# consumer config file Ref:consumer_config.properties -# provider config file Ref:provider_config.properties -config_center: - protocol: apollo - address: 106.12.25.204:8080 - group: testApplication_yang - cluster: dev - # 'namespace' can be used for router rule , default value is dubbo.properties - # but if you want to change router rule config file ,just open this item -# namespace: governance.properties - # 'config_file' is not necessary ,default : dubbo.properties - # but if you want to change config file ,just open this item -# config_file: mockDubbog.properties - -# application config required -application: - organization: "ikurento.com" - name: "BDTService" - module: "dubbogo user-info server" - version: "0.0.1" - owner: "ZX" +# use apollo config center for fetch config file +# default config file namespace is dubbo.properties +# consumer config file Ref:consumer_config.properties +# provider config file Ref:provider_config.properties +config_center: + protocol: apollo + address: 106.12.25.204:8080 + group: testApplication_yang + cluster: dev + # 'namespace' can be used for router rule , default value is dubbo.properties + # but if you want to change router rule config file ,just open this item +# namespace: governance.properties + # 'config_file' is not necessary ,default : dubbo.properties + # but if you want to change config file ,just open this item +# config_file: mockDubbog.properties + +# application config required +application: + organization: "ikurento.com" + name: "BDTService" + module: "dubbogo user-info server" + version: "0.0.1" + owner: "ZX" environment: "dev" \ No newline at end of file diff --git a/config/testdata/consumer_config_withoutProtocol.yml b/config/testdata/consumer_config_withoutProtocol.yml index 32bad8b91d..f3d9265442 100644 --- a/config/testdata/consumer_config_withoutProtocol.yml +++ b/config/testdata/consumer_config_withoutProtocol.yml @@ -77,6 +77,6 @@ protocol_conf: tcp_read_timeout: "1s" tcp_write_timeout: "5s" wait_timeout: "1s" - max_msg_len: 1024 + max_msg_len: 16498688 session_name: "client" diff --git a/config/testdata/provider_config.properties b/config/testdata/provider_config.properties index f7d70f5cd6..11b1909aa9 100644 --- a/config/testdata/provider_config.properties +++ b/config/testdata/provider_config.properties @@ -1,58 +1,58 @@ -filter= -application.organization=ikurento.com -application.name=BDTService -application.module=dubbogo user-info server -application.version=0.0.1 -application.owner=ZX -application.environment=dev -registries.hangzhouzk.protocol=zookeeper -registries.hangzhouzk.timeout=3s -registries.hangzhouzk.address=127.0.0.1:2181 -registries.hangzhouzk.username= -registries.hangzhouzk.password= -registries.shanghaizk.protocol=zookeeper -registries.shanghaizk.timeout=3s -registries.shanghaizk.address=127.0.0.1:2182 -registries.shanghaizk.username= -registries.shanghaizk.password= -services.UserProvider.registry=hangzhouzk,shanghaizk -services.UserProvider.filter= -services.UserProvider.tps.limiter=default -services.UserProvider.tps.limit.interval=60000 -services.UserProvider.tps.limit.rate=200 -services.UserProvider.tps.limit.strategy=slidingWindow -services.UserProvider.tps.limit.rejected.handler=default -services.UserProvider.execute.limit=200 -services.UserProvider.execute.limit.rejected.handler=default -services.UserProvider.protocol=dubbo -services.UserProvider.interface=com.ikurento.user.UserProvider -services.UserProvider.loadbalance=random -services.UserProvider.version=1.0 -services.UserProvider.group=as -services.UserProvider.warmup=100 -services.UserProvider.cluster=failover -services.UserProvider.methods[0].name=GetUser -services.UserProvider.methods[0].retries=1 -services.UserProvider.methods[0].loadbalance=random -services.UserProvider.methods[0].execute.limit=200 -services.UserProvider.methods[0].execute.limit.rejected.handler=default -protocols.dubbo.name=dubbo -protocols.dubbo.ip=127.0.0.1 -protocols.dubbo.port=20000 -protocol_conf.dubbo.session_number=700 -protocol_conf.dubbo.session_timeout=20s -protocol_conf.dubbo.gr_pool_size=120 -protocol_conf.dubbo.queue_len=64 -protocol_conf.dubbo.queue_number=6 -protocol_conf.dubbo.getty_session_param.compress_encoding=false -protocol_conf.dubbo.getty_session_param.tcp_no_delay=true -protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true -protocol_conf.dubbo.getty_session_param.keep_alive_period=120s -protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144 -protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536 -protocol_conf.dubbo.getty_session_param.pkg_wq_size=512 -protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s -protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s -protocol_conf.dubbo.getty_session_param.wait_timeout=1s -protocol_conf.dubbo.getty_session_param.max_msg_len=1024 +filter= +application.organization=ikurento.com +application.name=BDTService +application.module=dubbogo user-info server +application.version=0.0.1 +application.owner=ZX +application.environment=dev +registries.hangzhouzk.protocol=zookeeper +registries.hangzhouzk.timeout=3s +registries.hangzhouzk.address=127.0.0.1:2181 +registries.hangzhouzk.username= +registries.hangzhouzk.password= +registries.shanghaizk.protocol=zookeeper +registries.shanghaizk.timeout=3s +registries.shanghaizk.address=127.0.0.1:2182 +registries.shanghaizk.username= +registries.shanghaizk.password= +services.UserProvider.registry=hangzhouzk,shanghaizk +services.UserProvider.filter= +services.UserProvider.tps.limiter=default +services.UserProvider.tps.limit.interval=60000 +services.UserProvider.tps.limit.rate=200 +services.UserProvider.tps.limit.strategy=slidingWindow +services.UserProvider.tps.limit.rejected.handler=default +services.UserProvider.execute.limit=200 +services.UserProvider.execute.limit.rejected.handler=default +services.UserProvider.protocol=dubbo +services.UserProvider.interface=com.ikurento.user.UserProvider +services.UserProvider.loadbalance=random +services.UserProvider.version=1.0 +services.UserProvider.group=as +services.UserProvider.warmup=100 +services.UserProvider.cluster=failover +services.UserProvider.methods[0].name=GetUser +services.UserProvider.methods[0].retries=1 +services.UserProvider.methods[0].loadbalance=random +services.UserProvider.methods[0].execute.limit=200 +services.UserProvider.methods[0].execute.limit.rejected.handler=default +protocols.dubbo.name=dubbo +protocols.dubbo.ip=127.0.0.1 +protocols.dubbo.port=20000 +protocol_conf.dubbo.session_number=700 +protocol_conf.dubbo.session_timeout=20s +protocol_conf.dubbo.gr_pool_size=120 +protocol_conf.dubbo.queue_len=64 +protocol_conf.dubbo.queue_number=6 +protocol_conf.dubbo.getty_session_param.compress_encoding=false +protocol_conf.dubbo.getty_session_param.tcp_no_delay=true +protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true +protocol_conf.dubbo.getty_session_param.keep_alive_period=120s +protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144 +protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536 +protocol_conf.dubbo.getty_session_param.pkg_wq_size=512 +protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s +protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s +protocol_conf.dubbo.getty_session_param.wait_timeout=1s +protocol_conf.dubbo.getty_session_param.max_msg_len=1024 protocol_conf.dubbo.getty_session_param.session_name=server \ No newline at end of file diff --git a/config/testdata/provider_config.yml b/config/testdata/provider_config.yml index 7c46f9101a..de22b79d72 100644 --- a/config/testdata/provider_config.yml +++ b/config/testdata/provider_config.yml @@ -1,100 +1,100 @@ -# dubbo server yaml configure file - -filter: "" -# application config -application: - organization : "ikurento.com" - name : "BDTService" - module : "dubbogo user-info server" - version : "0.0.1" - owner : "ZX" - environment : "dev" - -registries : - "hangzhouzk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2181" - username: "" - password: "" - "shanghaizk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2182" - username: "" - password: "" - - -services: - "UserProvider": - registry: "hangzhouzk,shanghaizk" - filter: "" - # the name of limiter - tps.limiter: "default" - # the time unit of interval is ms - tps.limit.interval: 60000 - tps.limit.rate: 200 - # the name of strategy - tps.limit.strategy: "slidingWindow" - # the name of RejectedExecutionHandler - tps.limit.rejected.handler: "default" - # the concurrent request limitation of this service - # if the value < 0, it will not be limited. - execute.limit: "200" - # the name of RejectedExecutionHandler - execute.limit.rejected.handler: "default" - protocol : "dubbo" - # equivalent to interface of dubbo.xml - interface : "com.ikurento.user.UserProvider" - loadbalance: "random" - version: "1.0" - group: "as" - warmup: "100" - cluster: "failover" - methods: - - name: "GetUser" - retries: 1 - loadbalance: "random" - # the concurrent request limitation of this method - # if the value < 0, it will not be limited. - execute.limit: "200" - # the name of RejectedExecutionHandler - execute.limit.rejected.handler: "default" - -protocols: - "dubbo": - name: "dubbo" - # while using dubbo protocol, ip cannot is 127.0.0.1, because client of java-dubbo will get 'connection refuse' - ip : "127.0.0.1" - port : 20000 - #- name: "jsonrpc" - # ip: "127.0.0.1" - # port: 20001 - -shutdown_conf: - timeout: 60s - step_timeout: 10s - -protocol_conf: - dubbo: - session_number: 700 - session_timeout: "20s" - # gr_pool_size is recommended to be set to [cpu core number] * 10 - gr_pool_size: 120 - # queue_len is recommended to be set to 64 or 128 - queue_len: 64 - # queue_number is recommended to be set to gr_pool_size / 20 - queue_number: 6 - getty_session_param: - compress_encoding: false - tcp_no_delay: true - tcp_keep_alive: true - keep_alive_period: "120s" - tcp_r_buf_size: 262144 - tcp_w_buf_size: 65536 - pkg_wq_size: 512 - tcp_read_timeout: "1s" - tcp_write_timeout: "5s" - wait_timeout: "1s" - max_msg_len: 1024 - session_name: "server" +# dubbo server yaml configure file + +filter: "" +# application config +application: + organization : "ikurento.com" + name : "BDTService" + module : "dubbogo user-info server" + version : "0.0.1" + owner : "ZX" + environment : "dev" + +registries : + "hangzhouzk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + "shanghaizk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2182" + username: "" + password: "" + + +services: + "UserProvider": + registry: "hangzhouzk,shanghaizk" + filter: "" + # the name of limiter + tps.limiter: "default" + # the time unit of interval is ms + tps.limit.interval: 60000 + tps.limit.rate: 200 + # the name of strategy + tps.limit.strategy: "slidingWindow" + # the name of RejectedExecutionHandler + tps.limit.rejected.handler: "default" + # the concurrent request limitation of this service + # if the value < 0, it will not be limited. + execute.limit: "200" + # the name of RejectedExecutionHandler + execute.limit.rejected.handler: "default" + protocol : "dubbo" + # equivalent to interface of dubbo.xml + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + version: "1.0" + group: "as" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" + # the concurrent request limitation of this method + # if the value < 0, it will not be limited. + execute.limit: "200" + # the name of RejectedExecutionHandler + execute.limit.rejected.handler: "default" + +protocols: + "dubbo": + name: "dubbo" + # while using dubbo protocol, ip cannot is 127.0.0.1, because client of java-dubbo will get 'connection refuse' + ip : "127.0.0.1" + port : 20000 + #- name: "jsonrpc" + # ip: "127.0.0.1" + # port: 20001 + +shutdown_conf: + timeout: 60s + step_timeout: 10s + +protocol_conf: + dubbo: + session_number: 700 + session_timeout: "20s" + # gr_pool_size is recommended to be set to [cpu core number] * 10 + gr_pool_size: 120 + # queue_len is recommended to be set to 64 or 128 + queue_len: 64 + # queue_number is recommended to be set to gr_pool_size / 20 + queue_number: 6 + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 16498688 + session_name: "server" diff --git a/config/testdata/provider_config_withoutProtocol.yml b/config/testdata/provider_config_withoutProtocol.yml index 532d3005aa..3fa8100d84 100644 --- a/config/testdata/provider_config_withoutProtocol.yml +++ b/config/testdata/provider_config_withoutProtocol.yml @@ -76,5 +76,5 @@ protocol_conf: tcp_read_timeout: "1s" tcp_write_timeout: "5s" wait_timeout: "1s" - max_msg_len: 1024 + max_msg_len: 16498688 session_name: "server" diff --git a/doc/apache/release_note.md b/doc/apache/release_note.md index 747a3348a1..76fd6a5570 100644 --- a/doc/apache/release_note.md +++ b/doc/apache/release_note.md @@ -2,10 +2,11 @@ --- * 1 Check the time range of NOTICE; -* 2 Add the features to the feature list of README.md/README_CN.md/CHANGE.md; -* 3 Check whether every code file has the Apache License 2.0 or not; -* 4 There should not be author info(name & email etc) exist in code file; -* 5 Run all unit tests; -* 6 Run all samples in apache/dubbo-samples/golang; -* 7 Write "What's New" by releaser who should be an apache/dubbo-go committer; -* 8 And then, u can release a new version refer to [Apache 软件发版流程](./apache-release-procedure-20200306.md); \ No newline at end of file +* 2 Pls check the value of Version in common/constant. +* 3 Add the features to the feature list of README.md/README_CN.md/CHANGE.md; +* 4 Check whether every code file has the Apache License 2.0 or not; +* 5 There should not be author info(name & email etc) exist in code file; +* 6 Run all unit tests; +* 7 Run all samples in apache/dubbo-samples/golang; +* 8 Write "What's New" by releaser who should be an apache/dubbo-go committer; +* 9 And then, u can release a new version refer to [Apache 软件发版流程](./apache-release-procedure-20200306.md); \ No newline at end of file diff --git a/metadata/identifier/base_metadata_identifier.go b/metadata/identifier/base_metadata_identifier.go index 47c2e938ce..2d3d46aaf7 100644 --- a/metadata/identifier/base_metadata_identifier.go +++ b/metadata/identifier/base_metadata_identifier.go @@ -90,3 +90,20 @@ func withPathSeparator(path string) string { } return path } + +// BaseApplicationMetadataIdentifier is the base implement of BaseApplicationMetadataIdentifier interface +type BaseApplicationMetadataIdentifier struct { + Application string +} + +// getIdentifierKey returns string that format is application/param +func (madi *BaseApplicationMetadataIdentifier) getIdentifierKey(params ...string) string { + return madi.Application + joinParams(constant.KEY_SEPARATOR, params) +} + +// getFilePathKey returns string that format is metadata/application/revision +func (madi *BaseApplicationMetadataIdentifier) getFilePathKey(params ...string) string { + return constant.DEFAULT_PATH_TAG + + withPathSeparator(madi.Application) + + joinParams(constant.PATH_SEPARATOR, params) +} diff --git a/metadata/identifier/subscribe_metadata_identifier.go b/metadata/identifier/subscribe_metadata_identifier.go index b1e37db971..061a71301b 100644 --- a/metadata/identifier/subscribe_metadata_identifier.go +++ b/metadata/identifier/subscribe_metadata_identifier.go @@ -20,15 +20,24 @@ package identifier // SubscriberMetadataIdentifier is inherit baseMetaIdentifier with service params: Revision type SubscriberMetadataIdentifier struct { Revision string - MetadataIdentifier + BaseApplicationMetadataIdentifier +} + +func NewSubscriberMetadataIdentifier(application string, revision string) *SubscriberMetadataIdentifier { + return &SubscriberMetadataIdentifier{ + Revision: revision, + BaseApplicationMetadataIdentifier: BaseApplicationMetadataIdentifier{ + Application: application, + }, + } } // GetIdentifierKey returns string that format is service:Version:Group:Side:Revision func (mdi *SubscriberMetadataIdentifier) GetIdentifierKey() string { - return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.Revision) + return mdi.BaseApplicationMetadataIdentifier.getIdentifierKey(mdi.Revision) } // GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Revision func (mdi *SubscriberMetadataIdentifier) GetFilePathKey() string { - return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.Revision) + return mdi.BaseApplicationMetadataIdentifier.getFilePathKey(mdi.Revision) } diff --git a/metadata/report/consul/report.go b/metadata/report/consul/report.go index 0c9f9cb7c9..26998c4a98 100644 --- a/metadata/report/consul/report.go +++ b/metadata/report/consul/report.go @@ -44,6 +44,18 @@ type consulMetadataReport struct { client *consul.Client } +// GetAppMetadata get metadata info from consul +func (m *consulMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + // TODO will implement + panic("implement me") +} + +// PublishAppMetadata publish metadata info from consul +func (m *consulMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + // TODO will implement + panic("implement me") +} + // StoreProviderMetadata stores the metadata. func (m *consulMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error { kv := &consul.KVPair{Key: providerIdentifier.GetIdentifierKey(), Value: []byte(serviceDefinitions)} diff --git a/metadata/report/delegate/delegate_report.go b/metadata/report/delegate/delegate_report.go index 2cd9af8fec..92f4271b6d 100644 --- a/metadata/report/delegate/delegate_report.go +++ b/metadata/report/delegate/delegate_report.go @@ -148,6 +148,18 @@ func NewMetadataReport() (*MetadataReport, error) { return bmr, nil } +// GetAppMetadata delegate get metadata info +func (mr *MetadataReport) PublishAppMetadata(identifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + report := instance.GetMetadataReportInstance() + return report.PublishAppMetadata(identifier, info) +} + +// PublishAppMetadata delegate publish metadata info +func (mr *MetadataReport) GetAppMetadata(identifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + report := instance.GetMetadataReportInstance() + return report.GetAppMetadata(identifier) +} + // retry will do metadata failed reports collection by call metadata report sdk func (mr *MetadataReport) retry() bool { mr.failedReportsLock.RLock() @@ -204,7 +216,6 @@ func (mr *MetadataReport) storeMetadataTask(role int, identifier *identifier.Met if err != nil { logger.Errorf("storeProviderMetadataTask error in stage call metadata report to StoreProviderMetadata, msg is %+v", err) - panic(err) } } diff --git a/metadata/report/etcd/report.go b/metadata/report/etcd/report.go index 604e6da470..9c14a1a6d6 100644 --- a/metadata/report/etcd/report.go +++ b/metadata/report/etcd/report.go @@ -50,6 +50,18 @@ type etcdMetadataReport struct { root string } +// GetAppMetadata get metadata info from etcd +func (e *etcdMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + // TODO will implement + panic("implement me") +} + +// PublishAppMetadata publish metadata info to etcd +func (e *etcdMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + // TODO will implement + panic("implement me") +} + // StoreProviderMetadata will store the metadata // metadata including the basic info of the server, provider info, and other user custom info func (e *etcdMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error { diff --git a/metadata/report/nacos/report.go b/metadata/report/nacos/report.go index f62d02fffb..e4f2ab6712 100644 --- a/metadata/report/nacos/report.go +++ b/metadata/report/nacos/report.go @@ -50,6 +50,18 @@ type nacosMetadataReport struct { client config_client.IConfigClient } +// GetAppMetadata get metadata info from nacos +func (n *nacosMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + // TODO will implement + panic("implement me") +} + +// PublishAppMetadata publish metadata info to nacos +func (n *nacosMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + // TODO will implement + panic("implement me") +} + // StoreProviderMetadata stores the metadata. func (n *nacosMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error { return n.storeMetadata(vo.ConfigParam{ diff --git a/metadata/report/report.go b/metadata/report/report.go index dcb414209c..2d8774d05b 100644 --- a/metadata/report/report.go +++ b/metadata/report/report.go @@ -57,4 +57,10 @@ type MetadataReport interface { // GetServiceDefinition gets the service definition. GetServiceDefinition(*identifier.MetadataIdentifier) (string, error) + + // GetAppMetadata get metadata info from report + GetAppMetadata(*identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) + + // PublishAppMetadata publish metadata info to reportss + PublishAppMetadata(*identifier.SubscriberMetadataIdentifier, *common.MetadataInfo) error } diff --git a/metadata/report/zookeeper/report.go b/metadata/report/zookeeper/report.go index 580be9151a..cde74ea8b3 100644 --- a/metadata/report/zookeeper/report.go +++ b/metadata/report/zookeeper/report.go @@ -18,11 +18,13 @@ package zookeeper import ( + "encoding/json" "strings" "time" ) import ( + "github.com/dubbogo/go-zookeeper/zk" gxzookeeper "github.com/dubbogo/gost/database/kv/zk" ) @@ -30,6 +32,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" "github.com/apache/dubbo-go/metadata/identifier" "github.com/apache/dubbo-go/metadata/report" "github.com/apache/dubbo-go/metadata/report/factory" @@ -51,6 +54,36 @@ type zookeeperMetadataReport struct { rootDir string } +// GetAppMetadata get metadata info from zookeeper +func (m *zookeeperMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + k := m.rootDir + metadataIdentifier.GetFilePathKey() + data, _, err := m.client.GetContent(k) + if err != nil { + return nil, err + } + var metadataInfo common.MetadataInfo + err = json.Unmarshal(data, &metadataInfo) + if err != nil { + return nil, err + } + return &metadataInfo, nil +} + +// PublishAppMetadata publish metadata info to zookeeper +func (m *zookeeperMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + k := m.rootDir + metadataIdentifier.GetFilePathKey() + data, err := json.Marshal(info) + if err != nil { + return err + } + err = m.client.CreateWithValue(k, data) + if err == zk.ErrNodeExists { + logger.Debugf("Try to create the node data failed. In most cases, it's not a problem. ") + return nil + } + return err +} + // StoreProviderMetadata stores the metadata. func (m *zookeeperMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error { k := m.rootDir + providerIdentifier.GetFilePathKey() diff --git a/metadata/service/exporter/configurable/exporter.go b/metadata/service/exporter/configurable/exporter.go index 75e52d8d1b..7790621d08 100644 --- a/metadata/service/exporter/configurable/exporter.go +++ b/metadata/service/exporter/configurable/exporter.go @@ -60,9 +60,11 @@ func (exporter *MetadataServiceExporter) Export(url *common.URL) error { Port: url.SubURL.Port, }, } + serviceConfig.Registry = "N/A" serviceConfig.InterfaceName = constant.METADATA_SERVICE_NAME // identify this is a golang server serviceConfig.Params = map[string]string{} + serviceConfig.Group = config.GetApplicationConfig().Name // now the error will always be nil serviceConfig.Version, _ = exporter.metadataService.Version() diff --git a/metadata/service/exporter/configurable/exporter_test.go b/metadata/service/exporter/configurable/exporter_test.go index 9b2c8e4bec..fbc8df5e18 100644 --- a/metadata/service/exporter/configurable/exporter_test.go +++ b/metadata/service/exporter/configurable/exporter_test.go @@ -55,7 +55,7 @@ func TestConfigurableExporter(t *testing.T) { }, }) mockInitProviderWithSingleRegistry() - metadataService, _ := inmemory.NewMetadataService() + metadataService, _ := inmemory.GetInMemoryMetadataService() exported := NewMetadataServiceExporter(metadataService) t.Run("configurableExporterUrlNil", func(t *testing.T) { diff --git a/metadata/service/inmemory/metadata_service_proxy_factory.go b/metadata/service/inmemory/metadata_service_proxy_factory.go index becd804f67..cb45ea0265 100644 --- a/metadata/service/inmemory/metadata_service_proxy_factory.go +++ b/metadata/service/inmemory/metadata_service_proxy_factory.go @@ -19,6 +19,7 @@ package inmemory import ( "encoding/json" + "sync" ) import ( @@ -32,11 +33,23 @@ import ( func init() { factory := service.NewBaseMetadataServiceProxyFactory(createProxy) - extension.SetMetadataServiceProxyFactory(local, func() service.MetadataServiceProxyFactory { + extension.SetMetadataServiceProxyFactory(constant.DEFAULT_KEY, func() service.MetadataServiceProxyFactory { return factory }) } +var ( + factory service.MetadataServiceProxyFactory + once *sync.Once +) + +func GetInMemoryMetadataServiceProxyFactory() service.MetadataServiceProxyFactory { + once.Do(func() { + factory = service.NewBaseMetadataServiceProxyFactory(createProxy) + }) + return factory +} + // createProxy creates an instance of MetadataServiceProxy // we read the metadata from ins.Metadata() // and then create an Invoker instance @@ -59,33 +72,34 @@ func createProxy(ins registry.ServiceInstance) service.MetadataService { // buildStandardMetadataServiceURL will use standard format to build the metadata service url. func buildStandardMetadataServiceURL(ins registry.ServiceInstance) []*common.URL { ps := getMetadataServiceUrlParams(ins) + if ps[constant.PROTOCOL_KEY] == "" { + return nil + } res := make([]*common.URL, 0, len(ps)) sn := ins.GetServiceName() host := ins.GetHost() - for protocol, params := range ps { - - convertedParams := make(map[string][]string, len(params)) - for k, v := range params { - convertedParams[k] = []string{v} - } - - u := common.NewURLWithOptions(common.WithIp(host), - common.WithPath(constant.METADATA_SERVICE_NAME), - common.WithProtocol(protocol), - common.WithPort(params[constant.PORT_KEY]), - common.WithParams(convertedParams), - common.WithParamsValue(constant.GROUP_KEY, sn)) - res = append(res, u) + convertedParams := make(map[string][]string, len(ps)) + for k, v := range ps { + convertedParams[k] = []string{v} } + u := common.NewURLWithOptions(common.WithIp(host), + common.WithPath(constant.METADATA_SERVICE_NAME), + common.WithProtocol(ps[constant.PROTOCOL_KEY]), + common.WithPort(ps[constant.PORT_KEY]), + common.WithParams(convertedParams), + common.WithParamsValue(constant.GROUP_KEY, sn), + common.WithParamsValue(constant.INTERFACE_KEY, constant.METADATA_SERVICE_NAME)) + res = append(res, u) + return res } // getMetadataServiceUrlParams this will convert the metadata service url parameters to map structure // it looks like: // {"dubbo":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}} -func getMetadataServiceUrlParams(ins registry.ServiceInstance) map[string]map[string]string { +func getMetadataServiceUrlParams(ins registry.ServiceInstance) map[string]string { ps := ins.GetMetadata() - res := make(map[string]map[string]string, 2) + res := make(map[string]string, 2) if str, ok := ps[constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME]; ok && len(str) > 0 { err := json.Unmarshal([]byte(str), &res) diff --git a/metadata/service/inmemory/metadata_service_proxy_factory_test.go b/metadata/service/inmemory/metadata_service_proxy_factory_test.go index 011903f833..ea4f57ecc4 100644 --- a/metadata/service/inmemory/metadata_service_proxy_factory_test.go +++ b/metadata/service/inmemory/metadata_service_proxy_factory_test.go @@ -54,11 +54,10 @@ func TestCreateProxy(t *testing.T) { Enable: true, Healthy: true, } - pxy := createProxy(ins) assert.Nil(t, pxy) - ins.Metadata = map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`} + ins.Metadata = map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"protocol":"mock","timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}`} pxy = createProxy(ins) assert.NotNil(t, pxy) } diff --git a/metadata/service/inmemory/service.go b/metadata/service/inmemory/service.go index 8da78c3420..3b3d8857e7 100644 --- a/metadata/service/inmemory/service.go +++ b/metadata/service/inmemory/service.go @@ -35,16 +35,15 @@ import ( "github.com/apache/dubbo-go/metadata/service" ) +func init() { + extension.SetLocalMetadataService(constant.DEFAULT_KEY, GetInMemoryMetadataService) +} + // version will be used by Version func const ( version = "1.0.0" - local = "local" ) -func init() { - extension.SetMetadataService(local, NewMetadataService) -} - // MetadataService is store and query the metadata info in memory when each service registry type MetadataService struct { service.BaseMetadataService @@ -52,6 +51,9 @@ type MetadataService struct { subscribedServiceURLs *sync.Map serviceDefinitions *sync.Map lock *sync.RWMutex + mOnce *sync.Once + metadataInfo *common.MetadataInfo + metadataServiceURL *common.URL } var ( @@ -61,7 +63,7 @@ var ( // NewMetadataService: initiate a metadata service // it should be singleton -func NewMetadataService() (service.MetadataService, error) { +func GetInMemoryMetadataService() (service.MetadataService, error) { metadataServiceInitOnce.Do(func() { metadataServiceInstance = &MetadataService{ BaseMetadataService: service.NewBaseMetadataService(config.GetApplicationConfig().Name), @@ -69,6 +71,8 @@ func NewMetadataService() (service.MetadataService, error) { subscribedServiceURLs: &sync.Map{}, serviceDefinitions: &sync.Map{}, lock: &sync.RWMutex{}, + metadataInfo: nil, + mOnce: &sync.Once{}, } }) return metadataServiceInstance, nil @@ -153,11 +157,26 @@ func (mts *MetadataService) getSpecifiedService(services *sync.Map, serviceKey s // ExportURL can store the in memory func (mts *MetadataService) ExportURL(url *common.URL) (bool, error) { + if constant.METADATA_SERVICE_NAME == url.GetParam(constant.INTERFACE_KEY, "") { + mts.metadataServiceURL = url + return true, nil + } + mts.mOnce.Do(func() { + mts.metadataInfo = common.NewMetadataInfWithApp(config.GetApplicationConfig().Name) + }) + mts.metadataInfo.AddService(common.NewServiceInfoWithUrl(url)) return mts.addURL(mts.exportedServiceURLs, url), nil } // UnexportURL can remove the url store in memory func (mts *MetadataService) UnexportURL(url *common.URL) error { + if constant.METADATA_SERVICE_NAME == url.GetParam(constant.INTERFACE_KEY, "") { + mts.metadataServiceURL = nil + return nil + } + if mts.metadataInfo != nil { + mts.metadataInfo.RemoveService(common.NewServiceInfoWithUrl(url)) + } mts.removeURL(mts.exportedServiceURLs, url) return nil } @@ -193,12 +212,12 @@ func (mts *MetadataService) PublishServiceDefinition(url *common.URL) error { } // GetExportedURLs get all exported urls -func (mts *MetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) { +func (mts *MetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]*common.URL, error) { if serviceInterface == constant.ANY_VALUE { - return service.ConvertURLArrToIntfArr(mts.getAllService(mts.exportedServiceURLs)), nil + return mts.getAllService(mts.exportedServiceURLs), nil } else { serviceKey := definition.ServiceDescriperBuild(serviceInterface, group, version) - return service.ConvertURLArrToIntfArr(mts.getSpecifiedService(mts.exportedServiceURLs, serviceKey, protocol)), nil + return mts.getSpecifiedService(mts.exportedServiceURLs, serviceKey, protocol), nil } } @@ -220,6 +239,22 @@ func (mts *MetadataService) GetServiceDefinitionByServiceKey(serviceKey string) return v.(string), nil } +// GetMetadataInfo can get metadata in memory +func (mts *MetadataService) GetMetadataInfo(revision string) (*common.MetadataInfo, error) { + if revision == "" { + return mts.metadataInfo, nil + } + if mts.metadataInfo.CalAndGetRevision() != revision { + return nil, nil + } + return mts.metadataInfo, nil +} + +// GetExportedServiceURLs get exported service urls +func (mts *MetadataService) GetExportedServiceURLs() []*common.URL { + return mts.getAllService(mts.exportedServiceURLs) +} + // RefreshMetadata will always return true because it will be implement by remote service func (mts *MetadataService) RefreshMetadata(string, string) (bool, error) { return true, nil @@ -229,3 +264,13 @@ func (mts *MetadataService) RefreshMetadata(string, string) (bool, error) { func (mts *MetadataService) Version() (string, error) { return version, nil } + +// GetMetadataServiceURL get url of MetadataService +func (mts *MetadataService) GetMetadataServiceURL() *common.URL { + return mts.metadataServiceURL +} + +// GetMetadataServiceURL save url of MetadataService +func (mts *MetadataService) SetMetadataServiceURL(url *common.URL) { + mts.metadataServiceURL = url +} diff --git a/metadata/service/inmemory/service_proxy.go b/metadata/service/inmemory/service_proxy.go index fadf998b30..067722d0f1 100644 --- a/metadata/service/inmemory/service_proxy.go +++ b/metadata/service/inmemory/service_proxy.go @@ -37,13 +37,14 @@ import ( // so in client-side, if we want to get the metadata information, // we must call metadata service // this is the stub, or proxy -// for now, only GetExportedURLs need to be implemented +// for now, only GetMetadataInfo need to be implemented +// TODO use ProxyFactory to create proxy type MetadataServiceProxy struct { invkr protocol.Invoker - // golangServer bool } -func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) { +// nolint +func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]*common.URL, error) { siV := reflect.ValueOf(serviceInterface) gV := reflect.ValueOf(group) vV := reflect.ValueOf(version) @@ -60,75 +61,129 @@ func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group st res := m.invkr.Invoke(context.Background(), inv) if res.Error() != nil { logger.Errorf("could not get the metadata service from remote provider: %v", res.Error()) - return []interface{}{}, nil + return []*common.URL{}, nil } - urlStrs := res.Result().(*[]interface{}) + urlStrs := res.Result().([]string) + ret := make([]*common.URL, 0, len(urlStrs)) + for _, v := range urlStrs { + tempURL, err := common.NewURL(v) + if err != nil { + return []*common.URL{}, err + } + ret = append(ret, tempURL) + } + return ret, nil +} + +// nolint +func (m *MetadataServiceProxy) GetExportedServiceURLs() []*common.URL { + logger.Error("you should never invoke this implementation") + return nil +} + +// nolint +func (m *MetadataServiceProxy) GetMetadataServiceURL() *common.URL { + logger.Error("you should never invoke this implementation") + return nil +} - ret := make([]interface{}, 0, len(*urlStrs)) - return append(ret, *urlStrs...), nil +// nolint +func (m *MetadataServiceProxy) SetMetadataServiceURL(*common.URL) { + logger.Error("you should never invoke this implementation") } +// nolint func (m *MetadataServiceProxy) MethodMapper() map[string]string { return map[string]string{} } +// nolint func (m *MetadataServiceProxy) Reference() string { logger.Error("you should never invoke this implementation") return constant.METADATA_SERVICE_NAME } +// nolint func (m *MetadataServiceProxy) ServiceName() (string, error) { logger.Error("you should never invoke this implementation") return "", nil } +// nolint func (m *MetadataServiceProxy) ExportURL(url *common.URL) (bool, error) { logger.Error("you should never invoke this implementation") return false, nil } +// nolint func (m *MetadataServiceProxy) UnexportURL(url *common.URL) error { logger.Error("you should never invoke this implementation") return nil } +// nolint func (m *MetadataServiceProxy) SubscribeURL(url *common.URL) (bool, error) { logger.Error("you should never invoke this implementation") return false, nil } +// nolint func (m *MetadataServiceProxy) UnsubscribeURL(url *common.URL) error { logger.Error("you should never invoke this implementation") return nil } +// nolint func (m *MetadataServiceProxy) PublishServiceDefinition(url *common.URL) error { logger.Error("you should never invoke this implementation") return nil } +// nolint func (m *MetadataServiceProxy) GetSubscribedURLs() ([]*common.URL, error) { logger.Error("you should never invoke this implementation") return nil, nil } +// nolint func (m *MetadataServiceProxy) GetServiceDefinition(interfaceName string, group string, version string) (string, error) { logger.Error("you should never invoke this implementation") return "", nil } +// nolint func (m *MetadataServiceProxy) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) { logger.Error("you should never invoke this implementation") return "", nil } +// nolint func (m *MetadataServiceProxy) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) { logger.Error("you should never invoke this implementation") return false, nil } +// nolint func (m *MetadataServiceProxy) Version() (string, error) { logger.Error("you should never invoke this implementation") return "", nil } + +// nolint +func (m *MetadataServiceProxy) GetMetadataInfo(revision string) (*common.MetadataInfo, error) { + rV := reflect.ValueOf(revision) + const methodName = "getMetadataInfo" + inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(methodName), + invocation.WithArguments([]interface{}{rV.Interface()}), + invocation.WithReply(reflect.ValueOf(&common.MetadataInfo{}).Interface()), + invocation.WithAttachments(map[string]interface{}{constant.ASYNC_KEY: "false"}), + invocation.WithParameterValues([]reflect.Value{rV})) + res := m.invkr.Invoke(context.Background(), inv) + if res.Error() != nil { + logger.Errorf("could not get the metadata info from remote provider: %v", res.Error()) + return nil, res.Error() + } + metaDataInfo := res.Result().(*common.MetadataInfo) + return metaDataInfo, nil +} diff --git a/metadata/service/inmemory/service_proxy_test.go b/metadata/service/inmemory/service_proxy_test.go index 523d55ae65..c499c89226 100644 --- a/metadata/service/inmemory/service_proxy_test.go +++ b/metadata/service/inmemory/service_proxy_test.go @@ -90,5 +90,5 @@ func createPxy() service.MetadataService { Metadata: map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`}, } - return extension.GetMetadataServiceProxyFactory(local).GetProxy(ins) + return extension.GetMetadataServiceProxyFactory("").GetProxy(ins) } diff --git a/metadata/service/inmemory/service_test.go b/metadata/service/inmemory/service_test.go index e50cd6208a..a4cbaa5612 100644 --- a/metadata/service/inmemory/service_test.go +++ b/metadata/service/inmemory/service_test.go @@ -32,7 +32,7 @@ import ( ) func TestMetadataService(t *testing.T) { - mts, _ := NewMetadataService() + mts, _ := GetInMemoryMetadataService() serviceName := "com.ikurento.user.UserProvider" group := "group1" version := "0.0.1" diff --git a/metadata/service/remote/metadata_service_proxy_factory.go b/metadata/service/remote/metadata_service_proxy_factory.go deleted file mode 100644 index a1a8594282..0000000000 --- a/metadata/service/remote/metadata_service_proxy_factory.go +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package remote - -import ( - "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/metadata/service" -) - -func init() { - factory := service.NewBaseMetadataServiceProxyFactory(newMetadataServiceProxy) - extension.SetMetadataServiceProxyFactory(remote, func() service.MetadataServiceProxyFactory { - return factory - }) -} diff --git a/metadata/service/remote/remote.go b/metadata/service/remote/remote.go new file mode 100644 index 0000000000..1c3b4a3794 --- /dev/null +++ b/metadata/service/remote/remote.go @@ -0,0 +1,16 @@ +package remote + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/registry" +) + +// RemoteMetadataService for save and get metadata +type RemoteMetadataService interface { + // PublishMetadata publish the medata info of service from report + PublishMetadata(service string) + // GetMetadata get the medata info of service from report + GetMetadata(instance registry.ServiceInstance) (*common.MetadataInfo, error) + // PublishServiceDefinition will call remote metadata's StoreProviderMetadata to store url info and service definition + PublishServiceDefinition(url *common.URL) error +} diff --git a/metadata/service/remote/remote_impl/service.go b/metadata/service/remote/remote_impl/service.go new file mode 100644 index 0000000000..d7647894a3 --- /dev/null +++ b/metadata/service/remote/remote_impl/service.go @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package remote_impl + +import ( + "sync" +) + +import ( + "go.uber.org/atomic" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/metadata/definition" + "github.com/apache/dubbo-go/metadata/identifier" + "github.com/apache/dubbo-go/metadata/report/delegate" + "github.com/apache/dubbo-go/metadata/service/inmemory" + "github.com/apache/dubbo-go/metadata/service/remote" + "github.com/apache/dubbo-go/registry" +) + +// MetadataService is a implement of metadata service which will delegate the remote metadata report +// This is singleton +type RemoteMetadataServiceImpl struct { + *inmemory.MetadataService + exportedRevision atomic.String + subscribedRevision atomic.String + delegateReport *delegate.MetadataReport +} + +var ( + metadataServiceOnce sync.Once + remoteMetadataServiceImplInstance remote.RemoteMetadataService +) + +func init() { + extension.SetRemoteMetadataService(GetRemoteMetadataService) +} + +// GetRemoteMetadataService will create a new remote MetadataService instance +func GetRemoteMetadataService() (remote.RemoteMetadataService, error) { + var err error + metadataServiceOnce.Do(func() { + var mr *delegate.MetadataReport + mr, err = delegate.NewMetadataReport() + if err != nil { + return + } + // it will never return error + inms, _ := inmemory.GetInMemoryMetadataService() + remoteMetadataServiceImplInstance = &RemoteMetadataServiceImpl{ + // todo serviceName + //BaseMetadataService: service.NewBaseMetadataService(""), + MetadataService: inms.(*inmemory.MetadataService), + delegateReport: mr, + } + }) + return remoteMetadataServiceImplInstance, err +} + +// PublishMetadata publishes the metadata info of @service to remote metadata center +func (mts *RemoteMetadataServiceImpl) PublishMetadata(service string) { + info, err := mts.MetadataService.GetMetadataInfo("") + if err != nil { + logger.Errorf("GetMetadataInfo error[%v]", err) + return + } + if info.HasReported() { + return + } + id := identifier.NewSubscriberMetadataIdentifier(service, info.CalAndGetRevision()) + err = mts.delegateReport.PublishAppMetadata(id, info) + if err != nil { + logger.Errorf("Publishing metadata to error[%v]", err) + return + } + info.MarkReported() +} + +// GetMetadata get the medata info of service from report +func (mts *RemoteMetadataServiceImpl) GetMetadata(instance registry.ServiceInstance) (*common.MetadataInfo, error) { + revision := instance.GetMetadata()[constant.EXPORTED_SERVICES_REVISION_PROPERTY_NAME] + id := identifier.NewSubscriberMetadataIdentifier(instance.GetServiceName(), revision) + return mts.delegateReport.GetAppMetadata(id) +} + +// PublishServiceDefinition will call remote metadata's StoreProviderMetadata to store url info and service definition +func (mts *RemoteMetadataServiceImpl) PublishServiceDefinition(url *common.URL) error { + interfaceName := url.GetParam(constant.INTERFACE_KEY, "") + isGeneric := url.GetParamBool(constant.GENERIC_KEY, false) + if common.RoleType(common.PROVIDER).Role() == url.GetParam(constant.SIDE_KEY, "") { + if len(interfaceName) > 0 && !isGeneric { + sv := common.ServiceMap.GetServiceByServiceKey(url.Protocol, url.ServiceKey()) + sd := definition.BuildServiceDefinition(*sv, url) + id := &identifier.MetadataIdentifier{ + BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ + ServiceInterface: interfaceName, + Version: url.GetParam(constant.VERSION_KEY, ""), + Group: url.GetParam(constant.GROUP_KEY, constant.DUBBO), + Side: url.GetParam(constant.SIDE_KEY, constant.PROVIDER_PROTOCOL), + }, + } + mts.delegateReport.StoreProviderMetadata(id, sd) + return nil + } + logger.Errorf("publishProvider interfaceName is empty . providerUrl:%v ", url) + } else { + params := make(map[string]string, len(url.GetParams())) + url.RangeParams(func(key, value string) bool { + params[key] = value + return true + }) + id := &identifier.MetadataIdentifier{ + BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ + ServiceInterface: interfaceName, + Version: url.GetParam(constant.VERSION_KEY, ""), + Group: url.GetParam(constant.GROUP_KEY, constant.DUBBO), + Side: url.GetParam(constant.SIDE_KEY, "consumer"), + }, + } + mts.delegateReport.StoreConsumerMetadata(id, params) + return nil + } + + return nil +} diff --git a/metadata/service/remote/service_test.go b/metadata/service/remote/remote_impl/service_test.go similarity index 90% rename from metadata/service/remote/service_test.go rename to metadata/service/remote/remote_impl/service_test.go index d9e4d1477b..097f53d93e 100644 --- a/metadata/service/remote/service_test.go +++ b/metadata/service/remote/remote_impl/service_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package remote +package remote_impl import ( "fmt" @@ -55,6 +55,14 @@ func (mrf *metadataReportFactory) CreateMetadataReport(*common.URL) report.Metad type metadataReport struct{} +func (mr metadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { + panic("implement me") +} + +func (mr metadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { + panic("implement me") +} + func (metadataReport) StoreProviderMetadata(*identifier.MetadataIdentifier, string) error { return nil } @@ -96,14 +104,13 @@ func TestMetadataService(t *testing.T) { u, err := common.NewURL("mock://127.0.0.1:20000/?sync.report=true") assert.NoError(t, err) instance.GetMetadataReportInstance(u) - mts, err := newMetadataService() + mts, err := GetRemoteMetadataService() assert.NoError(t, err) - mts.(*MetadataService).setInMemoryMetadataService(mockInmemoryProc(t)) - _, _ = mts.RefreshMetadata("0.0.1", "0.0.1") + assert.NotNil(t, mts) } -func mockInmemoryProc(t *testing.T) *inmemory.MetadataService { - mts, _ := inmemory.NewMetadataService() +func TestMockInmemoryProc(t *testing.T) { + mts, _ := inmemory.GetInMemoryMetadataService() serviceName := "com.ikurento.user.UserProvider" group := "group1" version := "0.0.1" @@ -137,5 +144,4 @@ func mockInmemoryProc(t *testing.T) *inmemory.MetadataService { serviceKey := definition.ServiceDescriperBuild(serviceName, group, version) def2, _ := mts.GetServiceDefinitionByServiceKey(serviceKey) assert.Equal(t, expected, def2) - return mts.(*inmemory.MetadataService) } diff --git a/metadata/service/remote/service.go b/metadata/service/remote/service.go deleted file mode 100644 index 95e5c7f4df..0000000000 --- a/metadata/service/remote/service.go +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package remote - -import ( - "sync" -) - -import ( - "go.uber.org/atomic" -) - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/constant" - "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/config" - "github.com/apache/dubbo-go/metadata/definition" - "github.com/apache/dubbo-go/metadata/identifier" - "github.com/apache/dubbo-go/metadata/report/delegate" - "github.com/apache/dubbo-go/metadata/service" - "github.com/apache/dubbo-go/metadata/service/inmemory" -) - -// version will be used by Version func -const ( - version = "1.0.0" - remote = "remote" -) - -func init() { - extension.SetMetadataService(remote, newMetadataService) -} - -// MetadataService is a implement of metadata service which will delegate the remote metadata report -// This is singleton -type MetadataService struct { - service.BaseMetadataService - inMemoryMetadataService *inmemory.MetadataService - exportedRevision atomic.String - subscribedRevision atomic.String - delegateReport *delegate.MetadataReport -} - -var ( - metadataServiceOnce sync.Once - metadataServiceInstance *MetadataService -) - -// newMetadataService will create a new remote MetadataService instance -func newMetadataService() (service.MetadataService, error) { - var err error - metadataServiceOnce.Do(func() { - var mr *delegate.MetadataReport - mr, err = delegate.NewMetadataReport() - if err != nil { - return - } - // it will never return error - inms, _ := inmemory.NewMetadataService() - metadataServiceInstance = &MetadataService{ - BaseMetadataService: service.NewBaseMetadataService(config.GetApplicationConfig().Name), - inMemoryMetadataService: inms.(*inmemory.MetadataService), - delegateReport: mr, - } - }) - return metadataServiceInstance, err -} - -// setInMemoryMetadataService will replace the in memory metadata service by the specific param -func (mts *MetadataService) setInMemoryMetadataService(metadata *inmemory.MetadataService) { - mts.inMemoryMetadataService = metadata -} - -// ExportURL will be implemented by in memory service -func (mts *MetadataService) ExportURL(url *common.URL) (bool, error) { - return mts.inMemoryMetadataService.ExportURL(url) -} - -// UnexportURL remove @url's metadata -func (mts *MetadataService) UnexportURL(url *common.URL) error { - smi := identifier.NewServiceMetadataIdentifier(url) - smi.Revision = mts.exportedRevision.Load() - return mts.delegateReport.RemoveServiceMetadata(smi) -} - -// SubscribeURL will be implemented by in memory service -func (mts *MetadataService) SubscribeURL(url *common.URL) (bool, error) { - return mts.inMemoryMetadataService.SubscribeURL(url) -} - -// UnsubscribeURL will be implemented by in memory service -func (mts *MetadataService) UnsubscribeURL(url *common.URL) error { - // TODO remove call local. - return nil - // return mts.UnsubscribeURL(url) -} - -// PublishServiceDefinition will call remote metadata's StoreProviderMetadata to store url info and service definition -func (mts *MetadataService) PublishServiceDefinition(url *common.URL) error { - interfaceName := url.GetParam(constant.INTERFACE_KEY, "") - isGeneric := url.GetParamBool(constant.GENERIC_KEY, false) - if common.RoleType(common.PROVIDER).Role() == url.GetParam(constant.SIDE_KEY, "") { - if len(interfaceName) > 0 && !isGeneric { - sv := common.ServiceMap.GetServiceByServiceKey(url.Protocol, url.ServiceKey()) - sd := definition.BuildServiceDefinition(*sv, url) - id := &identifier.MetadataIdentifier{ - BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ - ServiceInterface: interfaceName, - Version: url.GetParam(constant.VERSION_KEY, ""), - Group: url.GetParam(constant.GROUP_KEY, constant.DUBBO), - Side: url.GetParam(constant.SIDE_KEY, constant.PROVIDER_PROTOCOL), - }, - } - mts.delegateReport.StoreProviderMetadata(id, sd) - return nil - } - logger.Errorf("publishProvider interfaceName is empty . providerUrl:%v ", url) - } else { - params := make(map[string]string, len(url.GetParams())) - url.RangeParams(func(key, value string) bool { - params[key] = value - return true - }) - id := &identifier.MetadataIdentifier{ - BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ - ServiceInterface: interfaceName, - Version: url.GetParam(constant.VERSION_KEY, ""), - Group: url.GetParam(constant.GROUP_KEY, constant.DUBBO), - Side: url.GetParam(constant.SIDE_KEY, "consumer"), - }, - } - mts.delegateReport.StoreConsumerMetadata(id, params) - return nil - } - - return nil -} - -// GetExportedURLs will be implemented by in memory service -func (mts *MetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) { - return mts.inMemoryMetadataService.GetExportedURLs(serviceInterface, group, version, protocol) -} - -// GetSubscribedURLs will be implemented by in memory service -func (mts *MetadataService) GetSubscribedURLs() ([]*common.URL, error) { - return mts.inMemoryMetadataService.GetSubscribedURLs() -} - -// GetServiceDefinition will be implemented by in memory service -func (mts *MetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) { - return mts.inMemoryMetadataService.GetServiceDefinition(interfaceName, group, version) -} - -// GetServiceDefinitionByServiceKey will be implemented by in memory service -func (mts *MetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) { - return mts.inMemoryMetadataService.GetServiceDefinitionByServiceKey(serviceKey) -} - -// RefreshMetadata will refresh the exported & subscribed metadata to remote metadata report from the inmemory metadata service -func (mts *MetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) { - if len(exportedRevision) != 0 && exportedRevision != mts.exportedRevision.Load() { - mts.exportedRevision.Store(exportedRevision) - urls, err := mts.inMemoryMetadataService.GetExportedURLs(constant.ANY_VALUE, "", "", "") - if err != nil { - logger.Errorf("Error occur when execute remote.MetadataService.RefreshMetadata, error message is %+v", err) - return false, err - } - logger.Infof("urls length = %v", len(urls)) - for _, ui := range urls { - - u, err := common.NewURL(ui.(string)) - if err != nil { - logger.Errorf("this is not valid url string: %s ", ui.(string)) - continue - } - id := identifier.NewServiceMetadataIdentifier(u) - id.Revision = mts.exportedRevision.Load() - if err := mts.delegateReport.SaveServiceMetadata(id, u); err != nil { - logger.Errorf("Error occur when execute remote.MetadataService.RefreshMetadata, error message is %+v", err) - return false, err - } - } - } - - if len(subscribedRevision) != 0 && subscribedRevision != mts.subscribedRevision.Load() { - mts.subscribedRevision.Store(subscribedRevision) - urls, err := mts.inMemoryMetadataService.GetSubscribedURLs() - if err != nil { - logger.Errorf("Error occur when execute remote.MetadataService.RefreshMetadata, error message is %v+", err) - return false, err - } - if len(urls) > 0 { - id := &identifier.SubscriberMetadataIdentifier{ - MetadataIdentifier: identifier.MetadataIdentifier{ - Application: config.GetApplicationConfig().Name, - }, - Revision: subscribedRevision, - } - if err := mts.delegateReport.SaveSubscribedData(id, urls); err != nil { - logger.Errorf("Error occur when execute remote.MetadataService.RefreshMetadata, error message is %+v", err) - return false, err - } - } - } - return true, nil -} - -// Version will return the remote service version -func (MetadataService) Version() (string, error) { - return version, nil -} diff --git a/metadata/service/remote/service_proxy.go b/metadata/service/remote/service_proxy.go deleted file mode 100644 index 241b3fc01a..0000000000 --- a/metadata/service/remote/service_proxy.go +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package remote - -import ( - "strings" -) - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/constant" - "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/config/instance" - "github.com/apache/dubbo-go/metadata/identifier" - "github.com/apache/dubbo-go/metadata/report" - "github.com/apache/dubbo-go/metadata/service" - "github.com/apache/dubbo-go/registry" -) - -type metadataServiceProxy struct { - serviceName string - revision string - report report.MetadataReport -} - -func (m *metadataServiceProxy) Reference() string { - return constant.METADATA_SERVICE_NAME -} - -func (m *metadataServiceProxy) ServiceName() (string, error) { - return m.serviceName, nil -} - -func (m *metadataServiceProxy) ExportURL(url *common.URL) (bool, error) { - logger.Error("you should never invoke this implementation") - return true, nil -} - -func (m *metadataServiceProxy) UnexportURL(url *common.URL) error { - logger.Error("you should never invoke this implementation") - return nil -} - -func (m *metadataServiceProxy) SubscribeURL(url *common.URL) (bool, error) { - logger.Error("you should never invoke this implementation") - return true, nil -} - -func (m *metadataServiceProxy) UnsubscribeURL(url *common.URL) error { - logger.Error("you should never invoke this implementation") - return nil -} - -func (m *metadataServiceProxy) PublishServiceDefinition(url *common.URL) error { - logger.Error("you should never invoke this implementation") - return nil -} - -func (m *metadataServiceProxy) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) { - urls, err := m.report.GetExportedURLs(&identifier.ServiceMetadataIdentifier{ - BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ - ServiceInterface: serviceInterface, - Version: version, - Group: group, - Side: constant.PROVIDER_PROTOCOL, - }, - Revision: m.revision, - Protocol: protocol, - }) - if err != nil { - return []interface{}{}, nil - } - var res []*common.URL - for _, s := range urls { - u, err := common.NewURL(s) - if err != nil { - logger.Errorf("could not parse the url string to URL structure", err) - continue - } - res = append(res, u) - } - return service.ConvertURLArrToIntfArr(res), nil -} - -func (m *metadataServiceProxy) MethodMapper() map[string]string { - return map[string]string{} -} - -func (m *metadataServiceProxy) GetSubscribedURLs() ([]*common.URL, error) { - logger.Error("you should never invoke this implementation") - return nil, nil -} - -func (m *metadataServiceProxy) GetServiceDefinition(interfaceName string, group string, version string) (string, error) { - return m.report.GetServiceDefinition(&identifier.MetadataIdentifier{ - BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{ - ServiceInterface: interfaceName, - Group: group, - Version: version, - Side: constant.PROVIDER_PROTOCOL, - }, - Application: m.serviceName, - }) -} - -func (m *metadataServiceProxy) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) { - params := parse(serviceKey) - return m.GetServiceDefinition(params[0], params[1], params[2]) -} - -func (m *metadataServiceProxy) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) { - logger.Error("you should never invoke this implementation") - return true, nil -} - -func (m metadataServiceProxy) Version() (string, error) { - return version, nil -} - -func newMetadataServiceProxy(ins registry.ServiceInstance) service.MetadataService { - revision := ins.GetMetadata()[constant.EXPORTED_SERVICES_REVISION_PROPERTY_NAME] - if len(revision) == 0 { - revision = constant.DEFAULT_REVISION - } - - return &metadataServiceProxy{ - serviceName: ins.GetServiceName(), - revision: revision, - report: instance.GetMetadataReportInstance(), - } -} - -func parse(key string) []string { - arr := make([]string, 3) - tmp := strings.SplitN(key, "/", 2) - if len(tmp) > 1 { - arr[0] = tmp[0] - key = tmp[1] - } - tmp = strings.SplitN(key, "/", 2) - if len(tmp) > 1 { - arr[2] = tmp[1] - key = tmp[0] - } - arr[1] = key - return arr -} diff --git a/metadata/service/remote/service_proxy_test.go b/metadata/service/remote/service_proxy_test.go deleted file mode 100644 index 546ee05352..0000000000 --- a/metadata/service/remote/service_proxy_test.go +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package remote - -import ( - "testing" -) - -import ( - "github.com/stretchr/testify/assert" -) - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/constant" - "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/config/instance" - "github.com/apache/dubbo-go/metadata/identifier" - "github.com/apache/dubbo-go/metadata/report" - "github.com/apache/dubbo-go/metadata/report/factory" - "github.com/apache/dubbo-go/metadata/service" - "github.com/apache/dubbo-go/registry" -) - -func TestMetadataServiceProxy_GetExportedURLs(t *testing.T) { - pxy := createProxy() - res, err := pxy.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) - assert.Nil(t, err) - assert.Len(t, res, 2) -} - -func TestMetadataServiceProxy_GetServiceDefinition(t *testing.T) { - pxy := createProxy() - res, err := pxy.GetServiceDefinition(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) - assert.Nil(t, err) - assert.Equal(t, "definition", res) -} - -// TestMetadataServiceProxy test those unimportant method -// in fact, we don't use them -func TestMetadataServiceProxy(t *testing.T) { - pxy := createProxy() - _, err := pxy.ServiceName() - assert.NoError(t, err) - err = pxy.PublishServiceDefinition(&common.URL{}) - assert.NoError(t, err) - _, err = pxy.Version() - assert.NoError(t, err) - _, err = pxy.GetSubscribedURLs() - assert.NoError(t, err) - err = pxy.UnsubscribeURL(&common.URL{}) - assert.NoError(t, err) - _, err = pxy.GetServiceDefinitionByServiceKey("any") - assert.NoError(t, err) - _, err = pxy.ExportURL(&common.URL{}) - assert.NoError(t, err) - _, err = pxy.SubscribeURL(&common.URL{}) - assert.NoError(t, err) - _ = pxy.MethodMapper() - err = pxy.UnexportURL(&common.URL{}) - assert.NoError(t, err) - _ = pxy.Reference() - _, err = pxy.RefreshMetadata(constant.ANY_VALUE, constant.ANY_VALUE) - assert.NoError(t, err) -} - -func createProxy() service.MetadataService { - prepareTest() - - ins := ®istry.DefaultServiceInstance{ - ID: "test-id", - ServiceName: "com.dubbo", - Host: "localhost", - Port: 8080, - Enable: true, - Healthy: true, - Metadata: map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`}, - } - return newMetadataServiceProxy(ins) -} - -func prepareTest() { - extension.SetMetadataReportFactory("mock", func() factory.MetadataReportFactory { - return &mockMetadataReportFactory{} - }) - u, _ := common.NewURL("mock://localhost") - instance.GetMetadataReportInstance(u) -} - -type mockMetadataReportFactory struct{} - -func (m *mockMetadataReportFactory) CreateMetadataReport(*common.URL) report.MetadataReport { - return &mockMetadataReport{} -} - -type mockMetadataReport struct{} - -func (m mockMetadataReport) StoreProviderMetadata(*identifier.MetadataIdentifier, string) error { - panic("implement me") -} - -func (m mockMetadataReport) StoreConsumerMetadata(*identifier.MetadataIdentifier, string) error { - panic("implement me") -} - -func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, *common.URL) error { - return nil -} - -func (m mockMetadataReport) RemoveServiceMetadata(*identifier.ServiceMetadataIdentifier) error { - panic("implement me") -} - -func (m mockMetadataReport) GetExportedURLs(*identifier.ServiceMetadataIdentifier) ([]string, error) { - return []string{"mock://localhost1", "mock://localhost2"}, nil -} - -func (m mockMetadataReport) SaveSubscribedData(*identifier.SubscriberMetadataIdentifier, string) error { - return nil -} - -func (m mockMetadataReport) GetSubscribedURLs(*identifier.SubscriberMetadataIdentifier) ([]string, error) { - panic("implement me") -} - -func (m mockMetadataReport) GetServiceDefinition(*identifier.MetadataIdentifier) (string, error) { - return "definition", nil -} diff --git a/metadata/service/service.go b/metadata/service/service.go index 1d90f8a516..3c83e94f73 100644 --- a/metadata/service/service.go +++ b/metadata/service/service.go @@ -47,10 +47,9 @@ type MetadataService interface { // the url should be unique // due to dubbo-go only support return array []interface{} in RPCService, so we should declare the return type as []interface{} // actually, it's []String - GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) - + GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]*common.URL, error) + // MethodMapper for rename dubbo method name MethodMapper() map[string]string - // GetExportedURLs will get the target subscribed url in metadata // the url should be unique GetSubscribedURLs() ([]*common.URL, error) @@ -62,6 +61,14 @@ type MetadataService interface { RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) // Version will return the metadata service version Version() (string, error) + // GetMetadataInfo will return metadata info + GetMetadataInfo(revision string) (*common.MetadataInfo, error) + // GetExportedServiceURLs will return exported service urls + GetExportedServiceURLs() []*common.URL + // GetMetadataServiceURL will return the url of metadata service + GetMetadataServiceURL() *common.URL + // SetMetadataServiceURL will save the url of metadata service + SetMetadataServiceURL(*common.URL) } // BaseMetadataService is used for the event logic for struct who will implement interface MetadataService @@ -78,6 +85,7 @@ func NewBaseMetadataService(serviceName string) BaseMetadataService { func (mts *BaseMetadataService) MethodMapper() map[string]string { return map[string]string{ "GetExportedURLs": "getExportedURLs", + "GetMetadataInfo": "getMetadataInfo", } } diff --git a/protocol/grpc/protoc-gen-dubbo/examples/Makefile b/protocol/grpc/protoc-gen-dubbo/examples/Makefile index 7893bbc51a..ffb92472f9 100644 --- a/protocol/grpc/protoc-gen-dubbo/examples/Makefile +++ b/protocol/grpc/protoc-gen-dubbo/examples/Makefile @@ -1,19 +1,19 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -grpc-gen: - protoc -I ./ helloworld.proto --go_out=plugins=grpc:. -dubbo-gen: - protoc -I ./ helloworld.proto --dubbo_out=plugins=grpc+dubbo:. +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +grpc-gen: + protoc -I ./ helloworld.proto --go_out=plugins=grpc:. +dubbo-gen: + protoc -I ./ helloworld.proto --dubbo_out=plugins=grpc+dubbo:. diff --git a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto index e73f72b1e0..44075024aa 100644 --- a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto +++ b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto @@ -1,40 +1,40 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "io.grpc.examples.helloworld"; -option java_outer_classname = "HelloWorldProto"; -option objc_class_prefix = "HLW"; - -package main; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package main; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/protocol/rest/config/reader/testdata/consumer_config.yml b/protocol/rest/config/reader/testdata/consumer_config.yml index 27d7fdafef..127bc966e7 100644 --- a/protocol/rest/config/reader/testdata/consumer_config.yml +++ b/protocol/rest/config/reader/testdata/consumer_config.yml @@ -1,74 +1,74 @@ -# dubbo client yaml configure file - -filter: "" - -config_type: - rest: "rest" - -# client -request_timeout : "100ms" -# connect timeout -connect_timeout : "100ms" -check: true -rest_server: "resty" -rest_produces: "*/*" -rest_consumes: "*/*" - -# application config -application: - organization : "ikurento.com" - name : "BDTService" - module : "dubbogo user-info client" - version : "0.0.1" - owner : "ZX" - environment : "dev" - -registries : - - "hangzhouzk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2181" - username: "" - password: "" - "shanghaizk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2182" - username: "" - password: "" - -references: - "UserProvider": - registry: "hangzhouzk,shanghaizk" - filter: "" - protocol : "rest" - version: "1.0" - group: "as" - interface : "com.ikurento.user.UserProvider" - url: "dubbo://127.0.0.1:20000/UserProvider" - cluster: "failover" - timeout: "3s" - rest_client: "resty1" - rest_produces: "application/xml" - rest_consumes: "application/xml" - methods : - - name: "GetUser" - retries: "3" - timeout: "5s" - rest_query_params: "1:userid,2:username" - rest_headers: "3:age" - rest_path_params: "4:time,2:name" - rest_body: 0 - rest_produces: "application/xml" - rest_consumes: "application/xml" - - params: - "serviceid": - "soa.com.ikurento.user.UserProvider" - "forks": 5 - -shutdown_conf: - timeout: 60s - step_timeout: 10s - +# dubbo client yaml configure file + +filter: "" + +config_type: + rest: "rest" + +# client +request_timeout : "100ms" +# connect timeout +connect_timeout : "100ms" +check: true +rest_server: "resty" +rest_produces: "*/*" +rest_consumes: "*/*" + +# application config +application: + organization : "ikurento.com" + name : "BDTService" + module : "dubbogo user-info client" + version : "0.0.1" + owner : "ZX" + environment : "dev" + +registries : + + "hangzhouzk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + "shanghaizk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2182" + username: "" + password: "" + +references: + "UserProvider": + registry: "hangzhouzk,shanghaizk" + filter: "" + protocol : "rest" + version: "1.0" + group: "as" + interface : "com.ikurento.user.UserProvider" + url: "dubbo://127.0.0.1:20000/UserProvider" + cluster: "failover" + timeout: "3s" + rest_client: "resty1" + rest_produces: "application/xml" + rest_consumes: "application/xml" + methods : + - name: "GetUser" + retries: "3" + timeout: "5s" + rest_query_params: "1:userid,2:username" + rest_headers: "3:age" + rest_path_params: "4:time,2:name" + rest_body: 0 + rest_produces: "application/xml" + rest_consumes: "application/xml" + + params: + "serviceid": + "soa.com.ikurento.user.UserProvider" + "forks": 5 + +shutdown_conf: + timeout: 60s + step_timeout: 10s + diff --git a/protocol/rest/config/reader/testdata/provider_config.yml b/protocol/rest/config/reader/testdata/provider_config.yml index 71d056e727..46400bd4ca 100644 --- a/protocol/rest/config/reader/testdata/provider_config.yml +++ b/protocol/rest/config/reader/testdata/provider_config.yml @@ -1,88 +1,88 @@ -# dubbo server yaml configure file - -filter: "" - -config_type: - rest: "rest" - -# application config -application: - organization : "ikurento.com" - name : "BDTService" - module : "dubbogo user-info server" - version : "0.0.1" - owner : "ZX" - environment : "dev" - -registries : - "hangzhouzk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2181" - username: "" - password: "" - "shanghaizk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2182" - username: "" - password: "" - -rest_server: "go-restful" -rest_produces: "*/*" -rest_consumes: "*/*" - -services: - "UserProvider": - registry: "hangzhouzk,shanghaizk" - filter: "" - # the name of limiter - tps.limiter: "default" - # the time unit of interval is ms - tps.limit.interval: 60000 - tps.limit.rate: 200 - # the name of strategy - tps.limit.strategy: "slidingWindow" - # the name of RejectedExecutionHandler - tps.limit.rejected.handler: "default" - # the concurrent request limitation of this service - # if the value < 0, it will not be limited. - execute.limit: "200" - # the name of RejectedExecutionHandler - execute.limit.rejected.handler: "default" - protocol : "rest" - # equivalent to interface of dubbo.xml - interface : "com.ikurento.user.UserProvider" - loadbalance: "random" - version: "1.0" - group: "as" - warmup: "100" - cluster: "failover" - rest_server: "go-restful1" - rest_produces: "*/*" - rest_consumes: "*/*" - methods: - - name: "GetUser" - retries: 1 - loadbalance: "random" - # the concurrent request limitation of this method - # if the value < 0, it will not be limited. - execute.limit: "200" - # the name of RejectedExecutionHandler - execute.limit.rejected.handler: "default" - rest_query_params: "1:userid,2:username" - rest_headers: "3:age" - rest_path_params: "4:time,2:name" - rest_body: 0 - rest_produces: "application/xml" - rest_consumes: "application/xml" - -protocols: - "rest": - name: "rest" - ip : "127.0.0.1" - port : 20000 - - - - +# dubbo server yaml configure file + +filter: "" + +config_type: + rest: "rest" + +# application config +application: + organization : "ikurento.com" + name : "BDTService" + module : "dubbogo user-info server" + version : "0.0.1" + owner : "ZX" + environment : "dev" + +registries : + "hangzhouzk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + "shanghaizk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2182" + username: "" + password: "" + +rest_server: "go-restful" +rest_produces: "*/*" +rest_consumes: "*/*" + +services: + "UserProvider": + registry: "hangzhouzk,shanghaizk" + filter: "" + # the name of limiter + tps.limiter: "default" + # the time unit of interval is ms + tps.limit.interval: 60000 + tps.limit.rate: 200 + # the name of strategy + tps.limit.strategy: "slidingWindow" + # the name of RejectedExecutionHandler + tps.limit.rejected.handler: "default" + # the concurrent request limitation of this service + # if the value < 0, it will not be limited. + execute.limit: "200" + # the name of RejectedExecutionHandler + execute.limit.rejected.handler: "default" + protocol : "rest" + # equivalent to interface of dubbo.xml + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + version: "1.0" + group: "as" + warmup: "100" + cluster: "failover" + rest_server: "go-restful1" + rest_produces: "*/*" + rest_consumes: "*/*" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" + # the concurrent request limitation of this method + # if the value < 0, it will not be limited. + execute.limit: "200" + # the name of RejectedExecutionHandler + execute.limit.rejected.handler: "default" + rest_query_params: "1:userid,2:username" + rest_headers: "3:age" + rest_path_params: "4:time,2:name" + rest_body: 0 + rest_produces: "application/xml" + rest_consumes: "application/xml" + +protocols: + "rest": + name: "rest" + ip : "127.0.0.1" + port : 20000 + + + + diff --git a/registry/base_configuration_listener.go b/registry/base_configuration_listener.go index 67dee9d0fa..75a32ec579 100644 --- a/registry/base_configuration_listener.go +++ b/registry/base_configuration_listener.go @@ -48,7 +48,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente bcl.dynamicConfiguration = config.GetEnvInstance().GetDynamicConfiguration() if bcl.dynamicConfiguration == nil { - // set configurators to empty + //set configurators to empty bcl.configurators = []config_center.Configurator{} return } @@ -56,7 +56,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente bcl.dynamicConfiguration.AddListener(key, listener) if rawConfig, err := bcl.dynamicConfiguration.GetInternalProperty(key, config_center.WithGroup(constant.DUBBO)); err != nil { - // set configurators to empty + //set configurators to empty bcl.configurators = []config_center.Configurator{} return } else if len(rawConfig) > 0 { @@ -68,7 +68,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente // Process the notification event once there's any change happens on the config. func (bcl *BaseConfigurationListener) Process(event *config_center.ConfigChangeEvent) { - logger.Infof("Notification of overriding rule, change type is: %v , raw config content is:%v", event.ConfigType, event.Value) + logger.Debugf("Notification of overriding rule, change type is: %v , raw config content is:%v", event.ConfigType, event.Value) if event.ConfigType == remoting.EventTypeDel { bcl.configurators = nil } else { diff --git a/registry/consul/service_discovery.go b/registry/consul/service_discovery.go index 6eba07d6c4..05d41a661a 100644 --- a/registry/consul/service_discovery.go +++ b/registry/consul/service_discovery.go @@ -366,59 +366,62 @@ func (csd *consulServiceDiscovery) GetRequestInstances(serviceNames []string, of return res } -func (csd *consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { - params := make(map[string]interface{}, 8) - params[watch_type] = watch_type_service - params[watch_service] = listener.ServiceName - params[watch_passingonly] = watch_passingonly_true - plan, err := watch.Parse(params) - if err != nil { - logger.Errorf("add listener for service %s,error:%v", listener.ServiceName, err) - return err - } - - plan.Handler = func(idx uint64, raw interface{}) { - services, ok := raw.([]*consul.ServiceEntry) - if !ok { - err = perrors.New("handler get non ServiceEntry type parameter") - return +func (csd *consulServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { + for _, v := range listener.GetServiceNames().Values() { + serviceName := v.(string) + params := make(map[string]interface{}, 8) + params[watch_type] = watch_type_service + params[watch_service] = serviceName + params[watch_passingonly] = watch_passingonly_true + plan, err := watch.Parse(params) + if err != nil { + logger.Errorf("add listener for service %s,error:%v", serviceName, err) + return err } - instances := make([]registry.ServiceInstance, 0, len(services)) - for _, ins := range services { - metadata := ins.Service.Meta - - // enable status - enableStr := metadata[enable] - delete(metadata, enable) - enable, _ := strconv.ParseBool(enableStr) - - // health status - status := ins.Checks.AggregatedStatus() - healthy := false - if status == consul.HealthPassing { - healthy = true + + plan.Handler = func(idx uint64, raw interface{}) { + services, ok := raw.([]*consul.ServiceEntry) + if !ok { + err = perrors.New("handler get non ServiceEntry type parameter") + return + } + instances := make([]registry.ServiceInstance, 0, len(services)) + for _, ins := range services { + metadata := ins.Service.Meta + + // enable status + enableStr := metadata[enable] + delete(metadata, enable) + enable, _ := strconv.ParseBool(enableStr) + + // health status + status := ins.Checks.AggregatedStatus() + healthy := false + if status == consul.HealthPassing { + healthy = true + } + instances = append(instances, ®istry.DefaultServiceInstance{ + ID: ins.Service.ID, + ServiceName: ins.Service.Service, + Host: ins.Service.Address, + Port: ins.Service.Port, + Enable: enable, + Healthy: healthy, + Metadata: metadata, + }) + } + e := csd.DispatchEventForInstances(serviceName, instances) + if e != nil { + logger.Errorf("Dispatching event got exception, service name: %s, err: %v", serviceName, err) } - instances = append(instances, ®istry.DefaultServiceInstance{ - ID: ins.Service.ID, - ServiceName: ins.Service.Service, - Host: ins.Service.Address, - Port: ins.Service.Port, - Enable: enable, - Healthy: healthy, - Metadata: metadata, - }) - } - e := csd.DispatchEventForInstances(listener.ServiceName, instances) - if e != nil { - logger.Errorf("Dispatching event got exception, service name: %s, err: %v", listener.ServiceName, err) } + go func() { + err = plan.RunWithConfig(csd.Config.Address, csd.Config) + if err != nil { + logger.Error("consul plan run failure!error:%v", err) + } + }() } - go func() { - err = plan.RunWithConfig(csd.Config.Address, csd.Config) - if err != nil { - logger.Error("consul plan run failure!error:%v", err) - } - }() return nil } diff --git a/registry/consul/service_discovery_test.go b/registry/consul/service_discovery_test.go index e68223d445..2ed7700e15 100644 --- a/registry/consul/service_discovery_test.go +++ b/registry/consul/service_discovery_test.go @@ -19,6 +19,8 @@ package consul import ( "fmt" + "github.com/apache/dubbo-go/registry/event" + gxset "github.com/dubbogo/gost/container/set" "math/rand" "strconv" "testing" @@ -150,7 +152,9 @@ func TestConsulServiceDiscovery_CRUD(t *testing.T) { // assert.Nil(t, err) // test AddListener - err = serviceDiscovery.AddListener(®istry.ServiceInstancesChangedListener{ServiceName: instance.GetServiceName()}) + hs := &gxset.HashSet{} + hs.Add(instance.GetServiceName()) + err = serviceDiscovery.AddListener(event.NewServiceInstancesChangedListener(hs)) assert.Nil(t, err) err = serviceDiscovery.Unregister(instance) assert.Nil(t, err) diff --git a/registry/etcdv3/service_discovery.go b/registry/etcdv3/service_discovery.go index 5e3e98f5dc..c4b13acd59 100644 --- a/registry/etcdv3/service_discovery.go +++ b/registry/etcdv3/service_discovery.go @@ -211,10 +211,17 @@ func (e *etcdV3ServiceDiscovery) GetRequestInstances(serviceNames []string, offs } // ----------------- event ---------------------- -// AddListener adds a new ServiceInstancesChangedListener +// AddListener adds a new ServiceInstancesChangedListenerImpl // see addServiceInstancesChangedListener in Java -func (e *etcdV3ServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { - return e.registerSreviceWatcher(listener.ServiceName) +func (e *etcdV3ServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { + for _, t := range listener.GetServiceNames().Values() { + serviceName := t.(string) + err := e.registerSreviceWatcher(serviceName) + if err != nil { + return err + } + } + return nil } // DispatchEventByServiceName dispatches the ServiceInstancesChangedEvent to service instance whose name is serviceName diff --git a/registry/event/base_configuration_listener.go b/registry/event/base_configuration_listener.go new file mode 100644 index 0000000000..c571c12158 --- /dev/null +++ b/registry/event/base_configuration_listener.go @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package event + +import ( + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/config" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/config_center" + "github.com/apache/dubbo-go/remoting" +) + +// nolint +type BaseConfigurationListener struct { + configurators []config_center.Configurator + dynamicConfiguration config_center.DynamicConfiguration + defaultConfiguratorFunc func(url *common.URL) config_center.Configurator +} + +// Configurators gets Configurator from config center +func (bcl *BaseConfigurationListener) Configurators() []config_center.Configurator { + return bcl.configurators +} + +// InitWith will init BaseConfigurationListener by @key+@Listener+@f +func (bcl *BaseConfigurationListener) InitWith(key string, listener config_center.ConfigurationListener, + f func(url *common.URL) config_center.Configurator) { + + bcl.dynamicConfiguration = config.GetEnvInstance().GetDynamicConfiguration() + if bcl.dynamicConfiguration == nil { + // set configurators to empty + bcl.configurators = []config_center.Configurator{} + return + } + bcl.defaultConfiguratorFunc = f + bcl.dynamicConfiguration.AddListener(key, listener) + if rawConfig, err := bcl.dynamicConfiguration.GetInternalProperty(key, + config_center.WithGroup(constant.DUBBO)); err != nil { + // set configurators to empty + bcl.configurators = []config_center.Configurator{} + return + } else if len(rawConfig) > 0 { + if err := bcl.genConfiguratorFromRawRule(rawConfig); err != nil { + logger.Error("bcl.genConfiguratorFromRawRule(rawConfig:%v) = error:%v", rawConfig, err) + } + } +} + +// Process the notification event once there's any change happens on the config. +func (bcl *BaseConfigurationListener) Process(event *config_center.ConfigChangeEvent) { + logger.Infof("Notification of overriding rule, change type is: %v , raw config content is:%v", event.ConfigType, event.Value) + if event.ConfigType == remoting.EventTypeDel { + bcl.configurators = nil + } else { + if err := bcl.genConfiguratorFromRawRule(event.Value.(string)); err != nil { + logger.Error(perrors.WithStack(err)) + } + } +} + +func (bcl *BaseConfigurationListener) genConfiguratorFromRawRule(rawConfig string) error { + urls, err := bcl.dynamicConfiguration.Parser().ParseToUrls(rawConfig) + if err != nil { + return perrors.WithMessage(err, "Failed to parse raw dynamic config and it will not take effect, the raw config is: "+ + rawConfig) + } + bcl.configurators = ToConfigurators(urls, bcl.defaultConfiguratorFunc) + return nil +} + +// OverrideUrl gets existing configuration rule and overrides provider url before exporting. +func (bcl *BaseConfigurationListener) OverrideUrl(url *common.URL) { + for _, v := range bcl.configurators { + v.Configure(url) + } +} + +// ToConfigurators converts @urls by @f to config_center.Configurators +func ToConfigurators(urls []*common.URL, f func(url *common.URL) config_center.Configurator) []config_center.Configurator { + if len(urls) == 0 { + return nil + } + var configurators []config_center.Configurator + for _, url := range urls { + if url.Protocol == constant.EMPTY_PROTOCOL { + configurators = []config_center.Configurator{} + break + } + + override := url.GetParams() + delete(override, constant.ANYHOST_KEY) + if len(override) == 0 { + continue + } + configurators = append(configurators, f(url)) + } + return configurators +} diff --git a/registry/event/customizable_service_instance_listener_test.go b/registry/event/customizable_service_instance_listener_test.go index b2dcd93fcc..5b73330d67 100644 --- a/registry/event/customizable_service_instance_listener_test.go +++ b/registry/event/customizable_service_instance_listener_test.go @@ -32,7 +32,6 @@ import ( ) func TestGetCustomizableServiceInstanceListener(t *testing.T) { - prepareMetadataServiceForTest() cus := GetCustomizableServiceInstanceListener() diff --git a/registry/event/event_publishing_service_deiscovery_test.go b/registry/event/event_publishing_service_deiscovery_test.go index 2448188b9d..4e3cfd1ce1 100644 --- a/registry/event/event_publishing_service_deiscovery_test.go +++ b/registry/event/event_publishing_service_deiscovery_test.go @@ -159,7 +159,7 @@ func (msd *ServiceDiscoveryA) GetRequestInstances(serviceNames []string, offset return nil } -func (msd *ServiceDiscoveryA) AddListener(listener *registry.ServiceInstancesChangedListener) error { +func (msd *ServiceDiscoveryA) AddListener(listener registry.ServiceInstancesChangedListener) error { return nil } diff --git a/registry/event/event_publishing_service_discovery.go b/registry/event/event_publishing_service_discovery.go index 6c418c1390..b01d6f0730 100644 --- a/registry/event/event_publishing_service_discovery.go +++ b/registry/event/event_publishing_service_discovery.go @@ -25,8 +25,8 @@ import ( import ( "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/observer" - "github.com/apache/dubbo-go/config" "github.com/apache/dubbo-go/metadata/service" + "github.com/apache/dubbo-go/metadata/service/inmemory" "github.com/apache/dubbo-go/registry" ) @@ -114,7 +114,7 @@ func (epsd *EventPublishingServiceDiscovery) GetRequestInstances(serviceNames [] } // AddListener add event listener -func (epsd *EventPublishingServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { +func (epsd *EventPublishingServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { extension.GetGlobalDispatcher().AddEventListener(listener) return epsd.serviceDiscovery.AddListener(listener) } @@ -152,5 +152,5 @@ func (epsd *EventPublishingServiceDiscovery) executeWithEvents(beforeEvent obser // getMetadataService returns metadata service instance func getMetadataService() (service.MetadataService, error) { - return extension.GetMetadataService(config.GetApplicationConfig().MetadataType) + return inmemory.GetInMemoryMetadataService() } diff --git a/registry/event/metadata_service_url_params_customizer.go b/registry/event/metadata_service_url_params_customizer.go index 2274cacab8..5e97e420b5 100644 --- a/registry/event/metadata_service_url_params_customizer.go +++ b/registry/event/metadata_service_url_params_customizer.go @@ -59,16 +59,12 @@ func (m *metadataServiceURLParamsMetadataCustomizer) Customize(instance registry logger.Errorf("could not find the metadata service", err) return } - serviceName := constant.METADATA_SERVICE_NAME - // error always is nil - version, _ := ms.Version() - group := instance.GetServiceName() - urls, err := ms.GetExportedURLs(serviceName, group, version, constant.ANY_VALUE) - if err != nil || len(urls) == 0 { - logger.Info("could not find the exported urls", err) + url := ms.GetMetadataServiceURL() + if url == nil { + logger.Errorf("the metadata service url is nil") return } - ps := m.convertToParams(urls) + ps := m.convertToParams(url) str, err := json.Marshal(ps) if err != nil { logger.Errorf("could not transfer the map to json", err) @@ -77,27 +73,17 @@ func (m *metadataServiceURLParamsMetadataCustomizer) Customize(instance registry instance.GetMetadata()[constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME] = string(str) } -func (m *metadataServiceURLParamsMetadataCustomizer) convertToParams(urls []interface{}) map[string]map[string]string { - // usually there will be only one protocol - res := make(map[string]map[string]string, 1) +func (m *metadataServiceURLParamsMetadataCustomizer) convertToParams(url *common.URL) map[string]string { // those keys are useless - - for _, ui := range urls { - u, err := common.NewURL(ui.(string)) - if err != nil { - logger.Errorf("could not parse the string to url: %s", ui.(string), err) + p := make(map[string]string, len(url.GetParams())) + for k, v := range url.GetParams() { + // we will ignore that + if !common.IncludeKeys.Contains(k) || len(v) == 0 || len(v[0]) == 0 { continue } - p := make(map[string]string, len(u.GetParams())) - for k, v := range u.GetParams() { - // we will ignore that - if m.exceptKeys.Contains(k) || len(v) == 0 || len(v[0]) == 0 { - continue - } - p[k] = v[0] - } - p[constant.PORT_KEY] = u.Port - res[u.Protocol] = p + p[k] = v[0] } - return res + p[constant.PORT_KEY] = url.Port + p[constant.PROTOCOL_KEY] = url.Protocol + return p } diff --git a/registry/event/metadata_service_url_params_customizer_test.go b/registry/event/metadata_service_url_params_customizer_test.go index 690c95dd95..3662c6a4b5 100644 --- a/registry/event/metadata_service_url_params_customizer_test.go +++ b/registry/event/metadata_service_url_params_customizer_test.go @@ -28,23 +28,10 @@ import ( import ( "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/config" - "github.com/apache/dubbo-go/metadata/service" "github.com/apache/dubbo-go/registry" ) -func prepareMetadataServiceForTest() { - config.GetApplicationConfig().MetadataType = "mock" - extension.SetMetadataService("mock", func() (service.MetadataService, error) { - return &mockMetadataService{ - urls: []interface{}{"mock://localhost:8080?a=b"}, - }, nil - }) -} - func TestMetadataServiceURLParamsMetadataCustomizer(t *testing.T) { - prepareMetadataServiceForTest() msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: gxset.NewSet()} assert.Equal(t, 0, msup.GetPriority()) diff --git a/registry/event/protocol_ports_metadata_customizer.go b/registry/event/protocol_ports_metadata_customizer.go index 8f401493b0..37f8810825 100644 --- a/registry/event/protocol_ports_metadata_customizer.go +++ b/registry/event/protocol_ports_metadata_customizer.go @@ -23,7 +23,6 @@ import ( ) import ( - "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" @@ -35,7 +34,8 @@ func init() { } // ProtocolPortsMetadataCustomizer will update the endpoints -type ProtocolPortsMetadataCustomizer struct{} +type ProtocolPortsMetadataCustomizer struct { +} // GetPriority will return 0, which means it will be invoked at the beginning func (p *ProtocolPortsMetadataCustomizer) GetPriority() int { @@ -53,16 +53,15 @@ func (p *ProtocolPortsMetadataCustomizer) Customize(instance registry.ServiceIns // 4 is enough... we don't have many protocol protocolMap := make(map[string]int, 4) - list, err := metadataService.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) - if err != nil || len(list) == 0 { + list := metadataService.GetExportedServiceURLs() + if list == nil || len(list) == 0 { logger.Debugf("Could not find exported urls", err) return } - for _, ui := range list { - u, err := common.NewURL(ui.(string)) + for _, u := range list { if err != nil || len(u.Protocol) == 0 { - logger.Errorf("the url string is invalid: %s", ui.(string), err) + logger.Errorf("the url string is invalid: %s", u, err) continue } @@ -82,9 +81,9 @@ func endpointsStr(protocolMap map[string]int) string { return "" } - endpoints := make([]endpoint, 0, len(protocolMap)) + endpoints := make([]registry.Endpoint, 0, len(protocolMap)) for k, v := range protocolMap { - endpoints = append(endpoints, endpoint{ + endpoints = append(endpoints, registry.Endpoint{ Port: v, Protocol: k, }) @@ -97,9 +96,3 @@ func endpointsStr(protocolMap map[string]int) string { } return string(str) } - -// nolint -type endpoint struct { - Port int `json:"port, omitempty"` - Protocol string `json:"protocol, omitempty"` -} diff --git a/registry/event/service_instances_changed_listener_impl.go b/registry/event/service_instances_changed_listener_impl.go new file mode 100644 index 0000000000..c0ab6927d5 --- /dev/null +++ b/registry/event/service_instances_changed_listener_impl.go @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package event + +import ( + "reflect" +) + +import ( + gxset "github.com/dubbogo/gost/container/set" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/common/observer" + "github.com/apache/dubbo-go/registry" + "github.com/apache/dubbo-go/remoting" +) + +// The Service Discovery Changed Event Listener +type ServiceInstancesChangedListenerImpl struct { + serviceNames *gxset.HashSet + listeners map[string]registry.NotifyListener + serviceUrls map[string][]*common.URL + revisionToMetadata map[string]*common.MetadataInfo + allInstances map[string][]registry.ServiceInstance +} + +func NewServiceInstancesChangedListener(services *gxset.HashSet) registry.ServiceInstancesChangedListener { + return &ServiceInstancesChangedListenerImpl{ + serviceNames: services, + listeners: make(map[string]registry.NotifyListener), + serviceUrls: make(map[string][]*common.URL), + revisionToMetadata: make(map[string]*common.MetadataInfo), + allInstances: make(map[string][]registry.ServiceInstance), + } +} + +// OnEvent on ServiceInstancesChangedEvent the service instances change event +func (lstn *ServiceInstancesChangedListenerImpl) OnEvent(e observer.Event) error { + ce, ok := e.(*registry.ServiceInstancesChangedEvent) + if !ok { + return nil + } + var err error + lstn.allInstances[ce.ServiceName] = ce.Instances + revisionToInstances := make(map[string][]registry.ServiceInstance) + newRevisionToMetadata := make(map[string]*common.MetadataInfo) + localServiceToRevisions := make(map[*common.ServiceInfo]*gxset.HashSet) + protocolRevisionsToUrls := make(map[string]map[*gxset.HashSet][]*common.URL) + newServiceURLs := make(map[string][]*common.URL) + + for _, instances := range lstn.allInstances { + for _, instance := range instances { + if instance.GetMetadata() == nil { + logger.Warnf("Instance metadata is nil: %s", instance.GetHost()) + continue + } + revision := instance.GetMetadata()[constant.EXPORTED_SERVICES_REVISION_PROPERTY_NAME] + if "0" == revision { + logger.Infof("Find instance without valid service metadata: %s", instance.GetHost()) + continue + } + subInstances := revisionToInstances[revision] + if subInstances == nil { + subInstances = make([]registry.ServiceInstance, 8) + } + revisionToInstances[revision] = append(subInstances, instance) + metadataInfo := lstn.revisionToMetadata[revision] + if metadataInfo == nil { + metadataInfo, err = lstn.getMetadataInfo(instance, revision) + if err != nil { + return err + } + } + instance.SetServiceMetadata(metadataInfo) + for _, service := range metadataInfo.Services { + if localServiceToRevisions[service] == nil { + localServiceToRevisions[service] = gxset.NewSet() + } + localServiceToRevisions[service].Add(revision) + } + + newRevisionToMetadata[revision] = metadataInfo + } + lstn.revisionToMetadata = newRevisionToMetadata + + for serviceInstance, revisions := range localServiceToRevisions { + revisionsToUrls := protocolRevisionsToUrls[serviceInstance.Protocol] + if revisionsToUrls == nil { + protocolRevisionsToUrls[serviceInstance.Protocol] = make(map[*gxset.HashSet][]*common.URL) + revisionsToUrls = protocolRevisionsToUrls[serviceInstance.Protocol] + } + urls := revisionsToUrls[revisions] + if urls != nil { + newServiceURLs[serviceInstance.GetMatchKey()] = urls + } else { + urls = make([]*common.URL, 0, 8) + for _, v := range revisions.Values() { + r := v.(string) + for _, i := range revisionToInstances[r] { + if i != nil { + urls = append(urls, i.ToURLs()...) + } + } + } + revisionsToUrls[revisions] = urls + newServiceURLs[serviceInstance.GetMatchKey()] = urls + } + } + lstn.serviceUrls = newServiceURLs + + for key, notifyListener := range lstn.listeners { + urls := lstn.serviceUrls[key] + for _, url := range urls { + notifyListener.Notify(®istry.ServiceEvent{ + Action: remoting.EventTypeAdd, + Service: url, + }) + } + } + } + return nil +} + +// getMetadataInfo get metadata info when METADATA_STORAGE_TYPE_PROPERTY_NAME is null +func (lstn *ServiceInstancesChangedListenerImpl) getMetadataInfo(instance registry.ServiceInstance, revision string) (*common.MetadataInfo, error) { + var metadataStorageType string + var metadataInfo *common.MetadataInfo + if instance.GetMetadata() == nil { + metadataStorageType = constant.DEFAULT_METADATA_STORAGE_TYPE + } else { + metadataStorageType = instance.GetMetadata()[constant.METADATA_STORAGE_TYPE_PROPERTY_NAME] + } + if metadataStorageType == constant.REMOTE_METADATA_STORAGE_TYPE { + remoteMetadataServiceImpl, err := extension.GetRemoteMetadataService() + if err != nil { + return nil, err + } + metadataInfo, err = remoteMetadataServiceImpl.GetMetadata(instance) + if err != nil { + return nil, err + } + } else { + var err error + proxyFactory := extension.GetMetadataServiceProxyFactory(constant.DEFAULT_KEY) + metadataService := proxyFactory.GetProxy(instance) + metadataInfo, err = metadataService.GetMetadataInfo(revision) + if err != nil { + return nil, err + } + } + return metadataInfo, nil +} + +// AddListenerAndNotify add notify listener and notify to listen service event +func (lstn *ServiceInstancesChangedListenerImpl) AddListenerAndNotify(serviceKey string, notify registry.NotifyListener) { + lstn.listeners[serviceKey] = notify + urls := lstn.serviceUrls[serviceKey] + for _, url := range urls { + notify.Notify(®istry.ServiceEvent{ + Action: remoting.EventTypeAdd, + Service: url, + }) + } +} + +// RemoveListener remove notify listener +func (lstn *ServiceInstancesChangedListenerImpl) RemoveListener(serviceKey string) { + delete(lstn.listeners, serviceKey) +} + +// GetServiceNames return all listener service names +func (lstn *ServiceInstancesChangedListenerImpl) GetServiceNames() *gxset.HashSet { + return lstn.serviceNames +} + +// Accept return true if the name is the same +func (lstn *ServiceInstancesChangedListenerImpl) Accept(e observer.Event) bool { + if ce, ok := e.(*registry.ServiceInstancesChangedEvent); ok { + return lstn.serviceNames.Contains(ce.ServiceName) + } + return false +} + +// GetPriority returns -1, it will be the first invoked listener +func (lstn *ServiceInstancesChangedListenerImpl) GetPriority() int { + return -1 +} + +// GetEventType returns ServiceInstancesChangedEvent +func (lstn *ServiceInstancesChangedListenerImpl) GetEventType() reflect.Type { + return reflect.TypeOf(®istry.ServiceInstancesChangedEvent{}) +} diff --git a/registry/event/service_revision_customizer.go b/registry/event/service_revision_customizer.go index 5d9668c412..179fd3d95d 100644 --- a/registry/event/service_revision_customizer.go +++ b/registry/event/service_revision_customizer.go @@ -28,7 +28,6 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/metadata/service" "github.com/apache/dubbo-go/registry" ) @@ -86,7 +85,7 @@ func (e *subscribedServicesRevisionMetadataCustomizer) Customize(instance regist logger.Errorf("could not find the subscribed url", err) } - revision := resolveRevision(service.ConvertURLArrToIntfArr(urls)) + revision := resolveRevision(urls) if len(revision) == 0 { revision = defaultRevision } @@ -97,18 +96,13 @@ func (e *subscribedServicesRevisionMetadataCustomizer) Customize(instance regist // so that we could use interface + method name as identifier and ignore the method params // per my understanding, it's enough because Dubbo actually ignore the url params. // please refer org.apache.dubbo.common.URL#toParameterString(java.lang.String...) -func resolveRevision(urls []interface{}) string { +func resolveRevision(urls []*common.URL) string { if len(urls) == 0 { - return "" + return "0" } candidates := make([]string, 0, len(urls)) - for _, ui := range urls { - u, err := common.NewURL(ui.(string)) - if err != nil { - logger.Errorf("could not parse the string to URL structure") - continue - } + for _, u := range urls { sk := u.GetParam(constant.INTERFACE_KEY, "") if len(u.Methods) == 0 { diff --git a/registry/event_listener.go b/registry/event_listener.go deleted file mode 100644 index 9e9ec2d5d4..0000000000 --- a/registry/event_listener.go +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package registry - -import ( - "reflect" -) - -import ( - "github.com/apache/dubbo-go/common/observer" -) - -// The Service Discovery Changed Event Listener -type ServiceInstancesChangedListener struct { - ServiceName string - ChangedNotify observer.ChangedNotify -} - -// OnEvent on ServiceInstancesChangedEvent the service instances change event -func (lstn *ServiceInstancesChangedListener) OnEvent(e observer.Event) error { - lstn.ChangedNotify.Notify(e) - return nil -} - -// Accept return true if the name is the same -func (lstn *ServiceInstancesChangedListener) Accept(e observer.Event) bool { - if ce, ok := e.(*ServiceInstancesChangedEvent); ok { - return ce.ServiceName == lstn.ServiceName - } - return false -} - -// GetPriority returns -1, it will be the first invoked listener -func (lstn *ServiceInstancesChangedListener) GetPriority() int { - return -1 -} - -// GetEventType returns ServiceInstancesChangedEvent -func (lstn *ServiceInstancesChangedListener) GetEventType() reflect.Type { - return reflect.TypeOf(&ServiceInstancesChangedEvent{}) -} diff --git a/registry/file/service_discovery.go b/registry/file/service_discovery.go index 40811dab8c..7f650d92b9 100644 --- a/registry/file/service_discovery.go +++ b/registry/file/service_discovery.go @@ -262,9 +262,9 @@ func (fssd *fileSystemServiceDiscovery) GetRequestInstances(serviceNames []strin } // ----------------- event ---------------------- -// AddListener adds a new ServiceInstancesChangedListener +// AddListener adds a new ServiceInstancesChangedListenerImpl // client -func (fssd *fileSystemServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { +func (fssd *fileSystemServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { // fssd.dynamicConfiguration.AddListener(listener.ServiceName) return nil } diff --git a/registry/nacos/service_discovery.go b/registry/nacos/service_discovery.go index f9e30d2a33..7cd804a5ce 100644 --- a/registry/nacos/service_discovery.go +++ b/registry/nacos/service_discovery.go @@ -212,39 +212,46 @@ func (n *nacosServiceDiscovery) GetRequestInstances(serviceNames []string, offse } // AddListener will add a listener -func (n *nacosServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { - return n.namingClient.Subscribe(&vo.SubscribeParam{ - ServiceName: listener.ServiceName, - SubscribeCallback: func(services []model.SubscribeService, err error) { - if err != nil { - logger.Errorf("Could not handle the subscribe notification because the err is not nil."+ - " service name: %s, err: %v", listener.ServiceName, err) - } - instances := make([]registry.ServiceInstance, 0, len(services)) - for _, service := range services { - // we won't use the nacos instance id here but use our instance id - metadata := service.Metadata - id := metadata[idKey] - - delete(metadata, idKey) - - instances = append(instances, ®istry.DefaultServiceInstance{ - ID: id, - ServiceName: service.ServiceName, - Host: service.Ip, - Port: int(service.Port), - Enable: service.Enable, - Healthy: true, - Metadata: metadata, - }) - } - - e := n.DispatchEventForInstances(listener.ServiceName, instances) - if e != nil { - logger.Errorf("Dispatching event got exception, service name: %s, err: %v", listener.ServiceName, err) - } - }, - }) +func (n *nacosServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { + for _, t := range listener.GetServiceNames().Values() { + serviceName := t.(string) + err := n.namingClient.Subscribe(&vo.SubscribeParam{ + ServiceName: serviceName, + SubscribeCallback: func(services []model.SubscribeService, err error) { + if err != nil { + logger.Errorf("Could not handle the subscribe notification because the err is not nil."+ + " service name: %s, err: %v", serviceName, err) + } + instances := make([]registry.ServiceInstance, 0, len(services)) + for _, service := range services { + // we won't use the nacos instance id here but use our instance id + metadata := service.Metadata + id := metadata[idKey] + + delete(metadata, idKey) + + instances = append(instances, ®istry.DefaultServiceInstance{ + ID: id, + ServiceName: service.ServiceName, + Host: service.Ip, + Port: int(service.Port), + Enable: service.Enable, + Healthy: true, + Metadata: metadata, + }) + } + + e := n.DispatchEventForInstances(serviceName, instances) + if e != nil { + logger.Errorf("Dispatching event got exception, service name: %s, err: %v", serviceName, err) + } + }, + }) + if err != nil { + return err + } + } + return nil } // DispatchEventByServiceName will dispatch the event for the service with the service name diff --git a/registry/nacos/service_discovery_test.go b/registry/nacos/service_discovery_test.go index 98460b0e96..3b8ac8e29c 100644 --- a/registry/nacos/service_discovery_test.go +++ b/registry/nacos/service_discovery_test.go @@ -25,6 +25,7 @@ import ( ) import ( + gxset "github.com/dubbogo/gost/container/set" "github.com/stretchr/testify/assert" ) @@ -35,6 +36,7 @@ import ( "github.com/apache/dubbo-go/common/observer/dispatcher" "github.com/apache/dubbo-go/config" "github.com/apache/dubbo-go/registry" + "github.com/apache/dubbo-go/registry/event" ) var testName = "test" @@ -156,9 +158,10 @@ func TestNacosServiceDiscovery_CRUD(t *testing.T) { // test dispatcher event err = serviceDiscovery.DispatchEventByServiceName(serviceName) assert.Nil(t, err) - + hs := &gxset.HashSet{} + hs.Add(serviceName) // test AddListener - err = serviceDiscovery.AddListener(®istry.ServiceInstancesChangedListener{ServiceName: serviceName}) + err = serviceDiscovery.AddListener(event.NewServiceInstancesChangedListener(hs)) assert.Nil(t, err) } diff --git a/registry/service_discovery.go b/registry/service_discovery.go index 5ab7683515..70b7b76d7b 100644 --- a/registry/service_discovery.go +++ b/registry/service_discovery.go @@ -72,9 +72,9 @@ type ServiceDiscovery interface { GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager // ----------------- event ---------------------- - // AddListener adds a new ServiceInstancesChangedListener + // AddListener adds a new ServiceInstancesChangedListenerImpl // see addServiceInstancesChangedListener in Java - AddListener(listener *ServiceInstancesChangedListener) error + AddListener(listener ServiceInstancesChangedListener) error // DispatchEventByServiceName dispatches the ServiceInstancesChangedEvent to service instance whose name is serviceName DispatchEventByServiceName(serviceName string) error diff --git a/registry/service_instance.go b/registry/service_instance.go index 6802cc0107..eeae7c77e5 100644 --- a/registry/service_instance.go +++ b/registry/service_instance.go @@ -17,10 +17,21 @@ package registry +import ( + "encoding/json" + "strconv" +) + import ( gxsort "github.com/dubbogo/gost/sort" ) +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/logger" +) + // ServiceInstance is the model class of an instance of a service, which is used for service registration and discovery. type ServiceInstance interface { @@ -44,18 +55,41 @@ type ServiceInstance interface { // GetMetadata will return the metadata GetMetadata() map[string]string + + // ToURLs + ToURLs() []*common.URL + + // GetEndPoints + GetEndPoints() []*Endpoint + + // Copy + Copy(endpoint *Endpoint) ServiceInstance + + // GetAddress + GetAddress() string + + // SetServiceMetadata + SetServiceMetadata(info *common.MetadataInfo) +} + +// nolint +type Endpoint struct { + Port int `json:"port, omitempty"` + Protocol string `json:"protocol, omitempty"` } // DefaultServiceInstance the default implementation of ServiceInstance // or change the ServiceInstance to be struct??? type DefaultServiceInstance struct { - ID string - ServiceName string - Host string - Port int - Enable bool - Healthy bool - Metadata map[string]string + ID string + ServiceName string + Host string + Port int + Enable bool + Healthy bool + Metadata map[string]string + ServiceMetadata *common.MetadataInfo + Address string } // GetID will return this instance's id. It should be unique. @@ -88,6 +122,67 @@ func (d *DefaultServiceInstance) IsHealthy() bool { return d.Healthy } +// GetAddress will return the ip:Port +func (d *DefaultServiceInstance) GetAddress() string { + if d.Address != "" { + return d.Address + } + if d.Port <= 0 { + d.Address = d.Host + } else { + d.Address = d.Host + ":" + strconv.Itoa(d.Port) + } + return d.Address +} + +// SetServiceMetadata save metadata in instance +func (d *DefaultServiceInstance) SetServiceMetadata(m *common.MetadataInfo) { + d.ServiceMetadata = m +} + +// ToURLs +func (d *DefaultServiceInstance) ToURLs() []*common.URL { + urls := make([]*common.URL, 0, 8) + for _, service := range d.ServiceMetadata.Services { + url := common.NewURLWithOptions(common.WithProtocol(service.Protocol), + common.WithIp(d.Host), common.WithPort(strconv.Itoa(d.Port)), + common.WithMethods(service.GetMethods()), common.WithParams(service.GetParams())) + urls = append(urls, url) + } + return urls +} + +// GetEndPoints get end points from metadata +func (d *DefaultServiceInstance) GetEndPoints() []*Endpoint { + rawEndpoints := d.Metadata[constant.SERVICE_INSTANCE_ENDPOINTS] + if len(rawEndpoints) == 0 { + return nil + } + var endpoints []*Endpoint + err := json.Unmarshal([]byte(rawEndpoints), &endpoints) + if err != nil { + logger.Errorf("json umarshal rawEndpoints[%s] catch error:%s", rawEndpoints, err.Error()) + return nil + } + return endpoints +} + +// Copy return a instance with different port +func (d *DefaultServiceInstance) Copy(endpoint *Endpoint) ServiceInstance { + dn := &DefaultServiceInstance{ + ID: d.ID, + ServiceName: d.ServiceName, + Host: d.Host, + Port: endpoint.Port, + Enable: d.Enable, + Healthy: d.Healthy, + Metadata: d.Metadata, + ServiceMetadata: d.ServiceMetadata, + } + dn.ID = d.GetAddress() + return dn +} + // GetMetadata will return the metadata, it will never return nil func (d *DefaultServiceInstance) GetMetadata() map[string]string { if d.Metadata == nil { diff --git a/registry/service_instances_changed_listener.go b/registry/service_instances_changed_listener.go new file mode 100644 index 0000000000..45b14f49f0 --- /dev/null +++ b/registry/service_instances_changed_listener.go @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package registry + +import ( + "github.com/apache/dubbo-go/common/observer" + gxset "github.com/dubbogo/gost/container/set" + "reflect" +) + +// ServiceInstancesChangedListener The Service Discovery Changed Event Listener +type ServiceInstancesChangedListener interface { + // OnEvent on ServiceInstancesChangedEvent the service instances change event + OnEvent(e observer.Event) error + // AddListenerAndNotify add notify listener and notify to listen service event + AddListenerAndNotify(serviceKey string, notify NotifyListener) + // RemoveListener remove notify listener + RemoveListener(serviceKey string) + // GetServiceNames return all listener service names + GetServiceNames() *gxset.HashSet + // Accept return true if the name is the same + Accept(e observer.Event) bool + // GetEventType returns ServiceInstancesChangedEvent + GetEventType() reflect.Type + // GetPriority returns -1, it will be the first invoked listener + GetPriority() int +} diff --git a/registry/servicediscovery/service_discovery_registry.go b/registry/servicediscovery/service_discovery_registry.go index 72b8dc6d4d..461a3cc208 100644 --- a/registry/servicediscovery/service_discovery_registry.go +++ b/registry/servicediscovery/service_discovery_registry.go @@ -19,8 +19,6 @@ package servicediscovery import ( "bytes" - "encoding/json" - "strconv" "strings" "sync" ) @@ -36,15 +34,14 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/common/observer" "github.com/apache/dubbo-go/config" "github.com/apache/dubbo-go/metadata/mapping" "github.com/apache/dubbo-go/metadata/service" "github.com/apache/dubbo-go/metadata/service/exporter/configurable" + "github.com/apache/dubbo-go/metadata/service/inmemory" "github.com/apache/dubbo-go/registry" "github.com/apache/dubbo-go/registry/event" "github.com/apache/dubbo-go/registry/servicediscovery/synthesizer" - "github.com/apache/dubbo-go/remoting" ) const ( @@ -70,9 +67,11 @@ type serviceDiscoveryRegistry struct { registeredListeners *gxset.HashSet subscribedURLsSynthesizers []synthesizer.SubscribedURLsSynthesizer serviceRevisionExportedURLsCache map[string]map[string][]*common.URL + serviceListeners map[string]registry.ServiceInstancesChangedListener } func newServiceDiscoveryRegistry(url *common.URL) (registry.Registry, error) { + tryInitMetadataService(url) serviceDiscovery, err := creatServiceDiscovery(url) @@ -82,7 +81,7 @@ func newServiceDiscoveryRegistry(url *common.URL) (registry.Registry, error) { subscribedServices := parseServices(url.GetParam(constant.SUBSCRIBED_SERVICE_NAMES_KEY, "")) subscribedURLsSynthesizers := synthesizer.GetAllSynthesizer() serviceNameMapping := extension.GetGlobalServiceNameMapping() - metaDataService, err := extension.GetMetadataService(config.GetApplicationConfig().MetadataType) + metaDataService, err := inmemory.GetInMemoryMetadataService() if err != nil { return nil, perrors.WithMessage(err, "could not init metadata service") } @@ -95,6 +94,7 @@ func newServiceDiscoveryRegistry(url *common.URL) (registry.Registry, error) { serviceRevisionExportedURLsCache: make(map[string]map[string][]*common.URL, 8), serviceNameMapping: serviceNameMapping, metaDataService: metaDataService, + serviceListeners: make(map[string]registry.ServiceInstancesChangedListener), }, nil } @@ -109,7 +109,19 @@ func (s *serviceDiscoveryRegistry) UnSubscribe(url *common.URL, listener registr if !shouldSubscribe(url) { return nil } - return s.metaDataService.UnsubscribeURL(url) + err := s.metaDataService.UnsubscribeURL(url) + if err != nil { + return err + } + services := s.getServices(url) + if services == nil { + return nil + } + // FIXME ServiceNames.String() is not good + serviceNamesKey := services.String() + l := s.serviceListeners[serviceNamesKey] + l.RemoveListener(url.ServiceKey()) + return nil } func creatServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) { @@ -130,7 +142,7 @@ func parseServices(literalServices string) *gxset.HashSet { if len(literalServices) == 0 { return set } - splitServices := strings.Split(literalServices, ",") + var splitServices = strings.Split(literalServices, ",") for _, s := range splitServices { if len(s) != 0 { set.Add(s) @@ -148,8 +160,10 @@ func (s *serviceDiscoveryRegistry) GetURL() *common.URL { } func (s *serviceDiscoveryRegistry) IsAvailable() bool { - // TODO(whether available depends on metadata service and service discovery) - return true + if s.serviceDiscovery.GetServices() == nil { + return false + } + return len(s.serviceDiscovery.GetServices().Values()) > 0 } func (s *serviceDiscoveryRegistry) Destroy() { @@ -164,6 +178,7 @@ func (s *serviceDiscoveryRegistry) Register(url *common.URL) error { return nil } ok, err := s.metaDataService.ExportURL(url) + if err != nil { logger.Errorf("The URL[%s] registry catch error:%s!", url.String(), err.Error()) return err @@ -200,30 +215,40 @@ func (s *serviceDiscoveryRegistry) Subscribe(url *common.URL, notify registry.No return perrors.Errorf("Should has at least one way to know which services this interface belongs to, "+ "subscription url:%s", url.String()) } - for _, srv := range services.Values() { - serviceName := srv.(string) - serviceInstances := s.serviceDiscovery.GetInstances(serviceName) - s.subscribe(url, notify, serviceName, serviceInstances) - listener := ®istry.ServiceInstancesChangedListener{ - ServiceName: serviceName, - ChangedNotify: &InstanceChangeNotify{ - notify: notify, - serviceDiscoveryRegistry: s, - }, + // FIXME ServiceNames.String() is not good + serviceNamesKey := services.String() + protocolServiceKey := url.ServiceKey() + ":" + url.Protocol + listener := s.serviceListeners[serviceNamesKey] + if listener == nil { + listener = event.NewServiceInstancesChangedListener(services) + for _, serviceNameTmp := range services.Values() { + serviceName := serviceNameTmp.(string) + instances := s.serviceDiscovery.GetInstances(serviceName) + err = listener.OnEvent(®istry.ServiceInstancesChangedEvent{ + ServiceName: serviceName, + Instances: instances, + }) + if err != nil { + logger.Warnf("[ServiceDiscoveryRegistry] ServiceInstancesChangedListenerImpl handle error:%v", err) + } } - s.registerServiceInstancesChangedListener(url, listener) } + s.serviceListeners[serviceNamesKey] = listener + listener.AddListenerAndNotify(protocolServiceKey, notify) + s.registerServiceInstancesChangedListener(url, listener) return nil } -func (s *serviceDiscoveryRegistry) registerServiceInstancesChangedListener(url *common.URL, listener *registry.ServiceInstancesChangedListener) { - listenerId := listener.ServiceName + ":" + getUrlKey(url) +func (s *serviceDiscoveryRegistry) registerServiceInstancesChangedListener(url *common.URL, listener registry.ServiceInstancesChangedListener) { + // FIXME ServiceNames.String() is not good + listenerId := listener.GetServiceNames().String() + ":" + getUrlKey(url) if !s.subscribedServices.Contains(listenerId) { err := s.serviceDiscovery.AddListener(listener) if err != nil { logger.Errorf("add listener[%s] catch error,url:%s err:%s", listenerId, url.String(), err.Error()) } } + } func getUrlKey(url *common.URL) string { @@ -254,25 +279,6 @@ func appendParam(buffer bytes.Buffer, paramKey string, url *common.URL) { buffer.WriteString(url.GetParam(paramKey, "")) } -func (s *serviceDiscoveryRegistry) subscribe(url *common.URL, notify registry.NotifyListener, - serviceName string, serviceInstances []registry.ServiceInstance) { - if len(serviceInstances) == 0 { - logger.Warnf("here is no instance in service[name : %s]", serviceName) - return - } - var subscribedURLs []*common.URL - subscribedURLs = append(subscribedURLs, s.getExportedUrls(url, serviceInstances)...) - if len(subscribedURLs) == 0 { - subscribedURLs = s.synthesizeSubscribedURLs(url, serviceInstances) - } - for _, url := range subscribedURLs { - notify.Notify(®istry.ServiceEvent{ - Action: remoting.EventTypeAdd, - Service: url, - }) - } -} - func (s *serviceDiscoveryRegistry) synthesizeSubscribedURLs(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL { var urls []*common.URL for _, syn := range s.subscribedURLsSynthesizers { @@ -316,304 +322,15 @@ func (s *serviceDiscoveryRegistry) findMappedServices(url *common.URL) *gxset.Ha return serviceNames } -func (s *serviceDiscoveryRegistry) getExportedUrls(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL { - var filterInstances []registry.ServiceInstance - for _, s := range serviceInstances { - if !s.IsEnable() || !s.IsHealthy() { - continue - } - metaData := s.GetMetadata() - _, ok1 := metaData[constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME] - _, ok2 := metaData[constant.METADATA_SERVICE_URLS_PROPERTY_NAME] - if !ok1 && !ok2 { - continue - } - filterInstances = append(filterInstances, s) - } - if len(filterInstances) == 0 { - return []*common.URL{} - } - s.prepareServiceRevisionExportedURLs(filterInstances) - subscribedURLs := s.cloneExportedURLs(subscribedURL, filterInstances) - return subscribedURLs -} - -func (s *serviceDiscoveryRegistry) getExportedUrlsByInst(serviceInstance registry.ServiceInstance) []*common.URL { - var urls []*common.URL - metadataStorageType := getExportedStoreType(serviceInstance) - proxyFactory := extension.GetMetadataServiceProxyFactory(metadataStorageType) - if proxyFactory == nil { - return urls - } - metadataService := proxyFactory.GetProxy(serviceInstance) - if metadataService == nil { - return urls - } - result, err := metadataService.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE) - if err != nil { - logger.Errorf("get exported urls catch error:%s,instance:%+v", err.Error(), serviceInstance) - return urls - } - - ret := make([]*common.URL, 0, len(result)) - for _, ui := range result { - - u, err := common.NewURL(ui.(string)) - if err != nil { - logger.Errorf("could not parse the url string to URL structure: %s", ui.(string), err) - continue - } - ret = append(ret, u) - } - return ret -} - -func (s *serviceDiscoveryRegistry) prepareServiceRevisionExportedURLs(serviceInstances []registry.ServiceInstance) { - s.lock.Lock() - // 1. expunge stale - s.expungeStaleRevisionExportedURLs(serviceInstances) - // 2. Initialize - s.initRevisionExportedURLs(serviceInstances) - s.lock.Unlock() -} - -func (s *serviceDiscoveryRegistry) expungeStaleRevisionExportedURLs(serviceInstances []registry.ServiceInstance) { - serviceName := serviceInstances[0].GetServiceName() - revisionExportedURLsMap, exist := s.serviceRevisionExportedURLsCache[serviceName] - if !exist { - return - } - existRevision := gxset.NewSet() - for k := range revisionExportedURLsMap { - existRevision.Add(k) - } - currentRevision := gxset.NewSet() - for _, s := range serviceInstances { - rv := getExportedServicesRevision(s) - if len(rv) != 0 { - currentRevision.Add(rv) - } - } - // staleRevisions = existedRevisions(copy) - currentRevisions - staleRevision := gxset.NewSet(existRevision.Values()...) - staleRevision.Remove(currentRevision.Values()...) - // remove exported URLs if staled - for _, s := range staleRevision.Values() { - delete(revisionExportedURLsMap, s.(string)) - } -} - -func (s *serviceDiscoveryRegistry) initRevisionExportedURLs(serviceInstances []registry.ServiceInstance) { - // initialize the revision exported URLs that the selected service instance exported - s.initSelectedRevisionExportedURLs(serviceInstances) - // initialize the revision exported URLs that other service instances exported - for _, serviceInstance := range serviceInstances { - s.initRevisionExportedURLsByInst(serviceInstance) - } -} - -func (s *serviceDiscoveryRegistry) initSelectedRevisionExportedURLs(serviceInstances []registry.ServiceInstance) { - for range serviceInstances { - selectServiceInstance := s.selectServiceInstance(serviceInstances) - revisionExportedURLs := s.initRevisionExportedURLsByInst(selectServiceInstance) - if len(revisionExportedURLs) > 0 { - // If the result is valid,break - break - } - } -} - -func (s *serviceDiscoveryRegistry) selectServiceInstance(serviceInstances []registry.ServiceInstance) registry.ServiceInstance { - size := len(serviceInstances) - if size == 0 { - return nil - } - if size == 1 { - return serviceInstances[0] - } - selectorName := s.url.GetParam(constant.SERVICE_INSTANCE_SELECTOR, "random") - selector, err := extension.GetServiceInstanceSelector(selectorName) - if err != nil { - logger.Errorf("get service instance selector cathe error:%s", err.Error()) - return nil - } - return selector.Select(s.url, serviceInstances) -} - -func (s *serviceDiscoveryRegistry) initRevisionExportedURLsByInst(serviceInstance registry.ServiceInstance) []*common.URL { - if serviceInstance == nil { - return nil - } - serviceName := serviceInstance.GetServiceName() - revision := getExportedServicesRevision(serviceInstance) - revisionExportedURLsMap := s.serviceRevisionExportedURLsCache[serviceName] - if revisionExportedURLsMap == nil { - revisionExportedURLsMap = make(map[string][]*common.URL, 4) - s.serviceRevisionExportedURLsCache[serviceName] = revisionExportedURLsMap - } - revisionExportedURLs := revisionExportedURLsMap[revision] - firstGet := false - if len(revisionExportedURLs) == 0 { - if len(revisionExportedURLsMap) > 0 { - // The case is that current ServiceInstance with the different revision - logger.Warnf("The ServiceInstance[id: %s, host : %s , port : %s] has different revision : %s"+ - ", please make sure the service [name : %s] is changing or not.", serviceInstance.GetID(), - serviceInstance.GetHost(), serviceInstance.GetPort(), revision, serviceInstance.GetServiceName()) - } else { - firstGet = true - } - revisionExportedURLs = s.getExportedUrlsByInst(serviceInstance) - if revisionExportedURLs != nil { - revisionExportedURLsMap[revision] = revisionExportedURLs - logger.Debugf("Get the exported URLs[size : %s, first : %s] from the target service "+ - "instance [id: %s , service : %s , host : %s , port : %s , revision : %s]", - len(revisionExportedURLs), firstGet, serviceInstance.GetID(), serviceInstance.GetServiceName(), - serviceInstance.GetHost(), serviceInstance.GetPort(), revision) - } - } else { - // Else, The cache is hit - logger.Debugf("Get the exported URLs[size : %s] from cache, the instance"+ - "[id: %s , service : %s , host : %s , port : %s , revision : %s]", len(revisionExportedURLs), firstGet, - serviceInstance.GetID(), serviceInstance.GetServiceName(), serviceInstance.GetHost(), - serviceInstance.GetPort(), revision) - } - return revisionExportedURLs -} - -func getExportedServicesRevision(serviceInstance registry.ServiceInstance) string { - metaData := serviceInstance.GetMetadata() - return metaData[constant.EXPORTED_SERVICES_REVISION_PROPERTY_NAME] -} - -func getExportedStoreType(serviceInstance registry.ServiceInstance) string { - metaData := serviceInstance.GetMetadata() - result, ok := metaData[constant.METADATA_STORAGE_TYPE_PROPERTY_NAME] - if !ok { - return constant.DEFAULT_METADATA_STORAGE_TYPE - } - return result -} - -func (s *serviceDiscoveryRegistry) cloneExportedURLs(url *common.URL, serviceInsances []registry.ServiceInstance) []*common.URL { - if len(serviceInsances) == 0 { - return []*common.URL{} - } - var clonedExportedURLs []*common.URL - removeParamSet := gxset.NewSet() - removeParamSet.Add(constant.PID_KEY) - removeParamSet.Add(constant.TIMESTAMP_KEY) - for _, serviceInstance := range serviceInsances { - templateExportURLs := s.getTemplateExportedURLs(url, serviceInstance) - host := serviceInstance.GetHost() - for _, u := range templateExportURLs { - port := strconv.Itoa(getProtocolPort(serviceInstance, u.Protocol)) - if u.Location != host || u.Port != port { - u.Port = port // reset port - u.Location = host + ":" + port // reset host - } - - cloneUrl := u.CloneExceptParams(removeParamSet) - clonedExportedURLs = append(clonedExportedURLs, cloneUrl) - } - } - return clonedExportedURLs -} - -type endpoint struct { - Port int `json:"port,omitempty"` - Protocol string `json:"protocol,omitempty"` -} - -func getProtocolPort(serviceInstance registry.ServiceInstance, protocol string) int { - md := serviceInstance.GetMetadata() - rawEndpoints := md[constant.SERVICE_INSTANCE_ENDPOINTS] - if len(rawEndpoints) == 0 { - return -1 - } - var endpoints []endpoint - err := json.Unmarshal([]byte(rawEndpoints), &endpoints) - if err != nil { - logger.Errorf("json umarshal rawEndpoints[%s] catch error:%s", rawEndpoints, err.Error()) - return -1 - } - for _, e := range endpoints { - if e.Protocol == protocol { - return e.Port - } - } - return -1 -} - -func (s *serviceDiscoveryRegistry) getTemplateExportedURLs(url *common.URL, serviceInstance registry.ServiceInstance) []*common.URL { - exportedURLs := s.getRevisionExportedURLs(serviceInstance) - if len(exportedURLs) == 0 { - return []*common.URL{} - } - return filterSubscribedURLs(url, exportedURLs) -} - -func (s *serviceDiscoveryRegistry) getRevisionExportedURLs(serviceInstance registry.ServiceInstance) []*common.URL { - if serviceInstance == nil { - return []*common.URL{} - } - serviceName := serviceInstance.GetServiceName() - revision := getExportedServicesRevision(serviceInstance) - s.lock.RLock() - revisionExportedURLsMap, exist := s.serviceRevisionExportedURLsCache[serviceName] - if !exist { - return []*common.URL{} - } - exportedURLs, exist := revisionExportedURLsMap[revision] - if !exist { - return []*common.URL{} - } - s.lock.RUnlock() - // Get a copy from source in order to prevent the caller trying to change the cached data - cloneExportedURLs := make([]*common.URL, len(exportedURLs)) - copy(cloneExportedURLs, exportedURLs) - return cloneExportedURLs -} - -func filterSubscribedURLs(subscribedURL *common.URL, exportedURLs []*common.URL) []*common.URL { - var filterExportedURLs []*common.URL - for _, url := range exportedURLs { - if url.GetParam(constant.INTERFACE_KEY, url.Path) != subscribedURL.GetParam(constant.INTERFACE_KEY, url.Path) { - break - } - if url.GetParam(constant.VERSION_KEY, "") != subscribedURL.GetParam(constant.VERSION_KEY, "") { - break - } - if url.GetParam(constant.GROUP_KEY, "") != subscribedURL.GetParam(constant.GROUP_KEY, "") { - break - } - if len(subscribedURL.Protocol) != 0 { - if subscribedURL.Protocol != url.Protocol { - break - } - } - filterExportedURLs = append(filterExportedURLs, url) - } - return filterExportedURLs -} - -type InstanceChangeNotify struct { - notify registry.NotifyListener - serviceDiscoveryRegistry *serviceDiscoveryRegistry -} - -func (icn *InstanceChangeNotify) Notify(event observer.Event) { - if se, ok := event.(*registry.ServiceInstancesChangedEvent); ok { - sdr := icn.serviceDiscoveryRegistry - sdr.subscribe(sdr.url.SubURL, icn.notify, se.ServiceName, se.Instances) - } -} - -var exporting = &atomic.Bool{} +var ( + exporting = &atomic.Bool{} +) // tryInitMetadataService will try to initialize metadata service // TODO (move to somewhere) func tryInitMetadataService(url *common.URL) { - ms, err := extension.GetMetadataService(config.GetApplicationConfig().MetadataType) + + ms, err := inmemory.GetInMemoryMetadataService() if err != nil { logger.Errorf("could not init metadata service", err) } diff --git a/registry/servicediscovery/service_discovery_registry_test.go b/registry/servicediscovery/service_discovery_registry_test.go index 6e1f228998..4d1e8a170c 100644 --- a/registry/servicediscovery/service_discovery_registry_test.go +++ b/registry/servicediscovery/service_discovery_registry_test.go @@ -45,7 +45,7 @@ var ( func TestServiceDiscoveryRegistry_Register(t *testing.T) { config.GetApplicationConfig().MetadataType = "mock" - extension.SetMetadataService("mock", func() (service service.MetadataService, err error) { + extension.SetLocalMetadataService("mock", func() (service service.MetadataService, err error) { service = &mockMetadataService{} return }) @@ -167,7 +167,7 @@ func (m *mockServiceDiscovery) GetRequestInstances([]string, int, int) map[strin panic("implement me") } -func (m *mockServiceDiscovery) AddListener(*registry.ServiceInstancesChangedListener) error { +func (m *mockServiceDiscovery) AddListener(registry.ServiceInstancesChangedListener) error { panic("implement me") } @@ -185,6 +185,26 @@ func (m *mockServiceDiscovery) DispatchEvent(*registry.ServiceInstancesChangedEv type mockMetadataService struct{} +func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]*common.URL, error) { + panic("implement me") +} + +func (m *mockMetadataService) GetMetadataInfo(revision string) (*common.MetadataInfo, error) { + panic("implement me") +} + +func (m *mockMetadataService) GetExportedServiceURLs() []*common.URL { + panic("implement me") +} + +func (m *mockMetadataService) GetMetadataServiceURL() *common.URL { + panic("implement me") +} + +func (m *mockMetadataService) SetMetadataServiceURL(url *common.URL) { + panic("implement me") +} + func (m *mockMetadataService) Reference() string { panic("implement me") } @@ -213,10 +233,6 @@ func (m *mockMetadataService) PublishServiceDefinition(*common.URL) error { return nil } -func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]interface{}, error) { - panic("implement me") -} - func (m *mockMetadataService) MethodMapper() map[string]string { panic("implement me") } diff --git a/registry/zookeeper/service_discovery.go b/registry/zookeeper/service_discovery.go index 92207c832f..3a48e9e7a6 100644 --- a/registry/zookeeper/service_discovery.go +++ b/registry/zookeeper/service_discovery.go @@ -269,11 +269,18 @@ func (zksd *zookeeperServiceDiscovery) GetRequestInstances(serviceNames []string } // AddListener ListenServiceEvent will add a data listener in service -func (zksd *zookeeperServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error { +func (zksd *zookeeperServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { zksd.listenLock.Lock() defer zksd.listenLock.Unlock() - zksd.listenNames = append(zksd.listenNames, listener.ServiceName) - zksd.csd.ListenServiceEvent(listener.ServiceName, zksd) + for _, t := range listener.GetServiceNames().Values() { + serviceName, ok := t.(string) + if !ok { + logger.Errorf("service name error %s", t) + continue + } + zksd.listenNames = append(zksd.listenNames, serviceName) + zksd.csd.ListenServiceEvent(serviceName, zksd) + } return nil } @@ -314,6 +321,7 @@ func (zksd *zookeeperServiceDiscovery) toCuratorInstance(instance registry.Servi pl["id"] = id pl["name"] = instance.GetServiceName() pl["metadata"] = instance.GetMetadata() + pl["@class"] = "org.apache.dubbo.registry.zookeeper.ZookeeperInstance" cuis := &curator_discovery.ServiceInstance{ Name: instance.GetServiceName(), ID: id, diff --git a/registry/zookeeper/service_discovery_test.go b/registry/zookeeper/service_discovery_test.go index aa3d77046c..96f009b8b3 100644 --- a/registry/zookeeper/service_discovery_test.go +++ b/registry/zookeeper/service_discovery_test.go @@ -18,6 +18,8 @@ package zookeeper import ( + "github.com/apache/dubbo-go/registry/event" + gxset "github.com/dubbogo/gost/container/set" "strconv" "sync" "testing" @@ -168,10 +170,9 @@ func TestAddListenerZookeeperServiceDiscovery(t *testing.T) { wg: wg, t: t, } - sicl := ®istry.ServiceInstancesChangedListener{ - ServiceName: testName, - ChangedNotify: tn, - } + hs := gxset.NewSet() + hs.Add(testName) + sicl := event.NewServiceInstancesChangedListener(hs) extension.SetAndInitGlobalDispatcher("direct") extension.GetGlobalDispatcher().AddEventListener(sicl) err = sd.AddListener(sicl) diff --git a/remoting/zookeeper/curator_discovery/service_instance.go b/remoting/zookeeper/curator_discovery/service_instance.go index 7acaf32f56..667ccc015a 100644 --- a/remoting/zookeeper/curator_discovery/service_instance.go +++ b/remoting/zookeeper/curator_discovery/service_instance.go @@ -20,10 +20,10 @@ package curator_discovery // ServiceInstance which define in curator-x-discovery, please refer to // https://github.com/apache/curator/blob/master/curator-x-discovery/src/main/java/org/apache/curator/x/discovery/ServiceInstance.java type ServiceInstance struct { - Name string - ID string - Address string - Port int - Payload interface{} - RegistrationTimeUTC int64 + Name string `json:"name,omitempty"` + ID string `json:"id,omitempty"` + Address string `json:"address,omitempty"` + Port int `json:"port,omitempty"` + Payload interface{} `json:"payload,omitempty"` + RegistrationTimeUTC int64 `json:"registrationTimeUTC,omitempty"` } diff --git a/test/integrate/dubbo/go-client/client.yml b/test/integrate/dubbo/go-client/client.yml index df44a13da3..93625d8020 100644 --- a/test/integrate/dubbo/go-client/client.yml +++ b/test/integrate/dubbo/go-client/client.yml @@ -1,61 +1,61 @@ -# dubbo client yaml configure file - - -check: true -# client -request_timeout : "3s" -# connect timeout -connect_timeout : "3s" - -# application config -application: - organization : "ikurento.com" - name : "BDTService" - module : "dubbogo user-info client" - version : "0.0.1" - owner : "ZX" - environment : "dev" - -registries : - "demoZk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2181" - username: "" - password: "" - - -references: - "UserProvider": - # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 - registry: "demoZk" - protocol : "dubbo" - interface : "com.ikurento.user.UserProvider" - cluster: "failover" - methods : - - name: "GetUser" - retries: 3 - - -protocol_conf: - dubbo: - reconnect_interval: 0 - connection_number: 2 - heartbeat_period: "5s" - session_timeout: "20s" - pool_size: 64 - pool_ttl: 600 - getty_session_param: - compress_encoding: false - tcp_no_delay: true - tcp_keep_alive: true - keep_alive_period: "120s" - tcp_r_buf_size: 262144 - tcp_w_buf_size: 65536 - pkg_rq_size: 1024 - pkg_wq_size: 512 - tcp_read_timeout: "1s" - tcp_write_timeout: "5s" - wait_timeout: "1s" - max_msg_len: 1024000 - session_name: "client" +# dubbo client yaml configure file + + +check: true +# client +request_timeout : "3s" +# connect timeout +connect_timeout : "3s" + +# application config +application: + organization : "ikurento.com" + name : "BDTService" + module : "dubbogo user-info client" + version : "0.0.1" + owner : "ZX" + environment : "dev" + +registries : + "demoZk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + + +references: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "demoZk" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + cluster: "failover" + methods : + - name: "GetUser" + retries: 3 + + +protocol_conf: + dubbo: + reconnect_interval: 0 + connection_number: 2 + heartbeat_period: "5s" + session_timeout: "20s" + pool_size: 64 + pool_ttl: 600 + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_rq_size: 1024 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 1024000 + session_name: "client" diff --git a/test/integrate/dubbo/go-client/go.mod b/test/integrate/dubbo/go-client/go.mod index 4c8ca0fb6a..0330244089 100644 --- a/test/integrate/dubbo/go-client/go.mod +++ b/test/integrate/dubbo/go-client/go.mod @@ -7,7 +7,7 @@ require ( //``` // RUN test ${PR_ORIGIN_REPO} && go mod edit -replace=github.com/apache/dubbo-go=github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID} || go get -u github.com/apache/dubbo-go@develop //``` - github.com/apache/dubbo-go v1.5.5 + github.com/apache/dubbo-go v1.5.6 github.com/apache/dubbo-go-hessian2 v1.9.1 ) diff --git a/test/integrate/dubbo/go-server/go.mod b/test/integrate/dubbo/go-server/go.mod index a51e9fc191..c9ace667fc 100644 --- a/test/integrate/dubbo/go-server/go.mod +++ b/test/integrate/dubbo/go-server/go.mod @@ -7,7 +7,7 @@ require ( //``` // RUN test ${PR_ORIGIN_REPO} && go mod edit -replace=github.com/apache/dubbo-go=github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID} || go get -u github.com/apache/dubbo-go@develop //``` - github.com/apache/dubbo-go v1.5.5 + github.com/apache/dubbo-go v1.5.6 github.com/apache/dubbo-go-hessian2 v1.9.1 ) diff --git a/test/integrate/dubbo/go-server/server.yml b/test/integrate/dubbo/go-server/server.yml index 8a17297b10..ff57a7d602 100644 --- a/test/integrate/dubbo/go-server/server.yml +++ b/test/integrate/dubbo/go-server/server.yml @@ -1,57 +1,57 @@ -# dubbo server yaml configure file - - -# application config -application: - organization : "ikurento.com" - name : "BDTService" - module : "dubbogo user-info server" - version : "0.0.1" - owner : "ZX" - environment : "dev" - -registries : - "demoZk": - protocol: "zookeeper" - timeout : "3s" - address: "127.0.0.1:2181" - -services: - "UserProvider": - # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 - registry: "demoZk" - protocol : "dubbo" - # 相当于dubbo.xml中的interface - interface : "com.ikurento.user.UserProvider" - loadbalance: "random" - warmup: "100" - cluster: "failover" - methods: - - name: "GetUser" - retries: 1 - loadbalance: "random" - -protocols: - "dubbo": - name: "dubbo" - port: 20000 - - -protocol_conf: - dubbo: - session_number: 700 - session_timeout: "20s" - getty_session_param: - compress_encoding: false - tcp_no_delay: true - tcp_keep_alive: true - keep_alive_period: "120s" - tcp_r_buf_size: 262144 - tcp_w_buf_size: 65536 - pkg_rq_size: 1024 - pkg_wq_size: 512 - tcp_read_timeout: "1s" - tcp_write_timeout: "5s" - wait_timeout: "1s" - max_msg_len: 1024000 - session_name: "server" +# dubbo server yaml configure file + + +# application config +application: + organization : "ikurento.com" + name : "BDTService" + module : "dubbogo user-info server" + version : "0.0.1" + owner : "ZX" + environment : "dev" + +registries : + "demoZk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + +services: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "demoZk" + protocol : "dubbo" + # 相当于dubbo.xml中的interface + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" + +protocols: + "dubbo": + name: "dubbo" + port: 20000 + + +protocol_conf: + dubbo: + session_number: 700 + session_timeout: "20s" + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_rq_size: 1024 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 1024000 + session_name: "server"